Reading the documentation on the front page, it is not clear to me what the best practice for raising errors from a command's Run func is?
Looking at usage of cobra in other projects, the way seems to be just to return os.Exit(1) from the body of the Run func. I'm a total Go noob so my instinct is probably wrong, but this didn't feel quite 'right' to me. Wouldn't that bypass any PostRun hooks? They feel like lifecycle events that should always get a chance to run though.
Then I read to the bottom of issue https://github.com/spf13/cobra/issues/67 and I can see some code got merged four years ago adding a RunE hook which returns error. (Forgive me if I missed it but it seems this is not mentioned in the docs anywhere? https://github.com/spf13/cobra#prerun-and-postrun-hooks Are they deprecated?)
This seemed like what I wanted, but the downside is this causes the 'usage' help text to be output. But that's not always appropriate - maybe the user gave perfectly good args to the command but somewhere in the processing of the job an error had to be returned.
So I have gone back to calling os.Exit from the body of Run. In the end this is fine for my use case.
All this is just to say it would be good to have the framework's opinion on how to handle errors expressed in the docs somewhere.
To suppress the usage, use the SilenceUsage field.
However, I totally agree with you on that it needs some kind of documentation.
Currently wondering why PersistentPostRuns are not executed when RunE returns an error. This is, in my opinion, not obvious. And I would like to still run the PersistentPostRun, instead of just exiting.
Any update on this topic please ?
I am also looking at good practices about errors handling in Cobra. The RunE seems to be really good, but the fact that there is nothing on the documentation is confusing, like if it was not good to use it.
After reading the Command code for a while, I don't see a really flexible way to decide how to handle errors at runtime. This is the approach we've ended up on:
func main() {
if err := command.RootCmd.Execute(); err != nil {
if err != command.SilentErr {
fmt.Fprintln(os.Stderr, err)
}
os.Exit(1)
}
}
package command
var SilentErr = errors.New("SilentErr")
var RootCmd = &cobra.Command{
// ...
SilenceErrors: true,
SilenceUsage: true,
}
func init() {
RootCmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
cmd.Println(err)
cmd.Println(cmd.UsageString())
return SilentErr
})
}
After this, we use RunE for all commands.
The features of this approach are:
main().Drawbacks:
unknown command "SUBCMD" for "CMD" errors.This issue is being marked as stale due to a long period of inactivity
Most helpful comment
After reading the Command code for a while, I don't see a really flexible way to decide how to handle errors at runtime. This is the approach we've ended up on:
After this, we use
RunEfor all commands.The features of this approach are:
main().Drawbacks:
unknown command "SUBCMD" for "CMD"errors.Ref. https://github.com/spf13/cobra/issues/340