cobra: Return "unknown command" error for unknown subcommands.
Right now there is a difference in handling between unknown command and unknown subcommand. Let’s consider the example:
package main
import "github.com/spf13/cobra"
func main() {
subCmd := &cobra.Command{
Use: "foo",
}
subCmd.AddCommand(&cobra.Command{
Use: "bar",
Run: func(cmd *cobra.Command, args []string) {
cmd.Println("bar")
},
})
subCmd.AddCommand(&cobra.Command{
Use: "baz",
Run: func(cmd *cobra.Command, args []string) {
cmd.Println("baz")
},
})
rootCmd := &cobra.Command{
Use: "test",
}
rootCmd.AddCommand(subCmd)
rootCmd.Execute()
}
When I run it as ./test unknown I get ‘unknown command’ error:
Error: unknown command "unknown" for "test"
Run 'test --help' for usage.
If I run it as ./test foo unknown I receive help message:
$ go run main.go foo unknown
Usage:
test foo [command]
Available Commands:
bar
baz
Flags:
-h, --help help for foo
Use "test foo [command] --help" for more information about a command.
It seems very much like inconsistency.
I suppose that we don’t need to return flag.ErrHelp on not runnable command and treat it like “unknown subcommand”.
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 14
- Comments: 17
instead of setting,
PositionalArgs: MaximumNArgs(0), you can setArgs: cobra.NoArgs, the result of which is that the subcommand’s ‘unknown command’ behavior will be consistent with that of the top-level command.Runneeds to be set to some dummy function. e.g.:Since this issue had quite a bit of discussion and reaction I’m removing the stale label and marking as needing more triage. I’m a new maintainer so I am unsure if this had been discussed more out of band from this issue. The fact that the first comment mentioned it was a known/accepted state of things makes me unsure if there is intent to fix it.
Since numerous users are asking for it, it seems very reasonable though.
This is just broken - please fix
Unfortunately not, referring to your example Original returning an error (by cobra), the usage but exit 0 With Run we can return an error (by ourselves), optionally the usage and Exit 1, but as you can see, the Usage line is double (what I’m referring to in my last comment) - Which is technically the truth, since we’ve provided a Run() function! (It can be run by itself with persistentFlags OR using a subcommand which will have its own flags) With Run + SilenceUsage everywhere no change in the effective Usage() output
That’s why - since we don’t want to change break the current behaviour, I’m suggesting that we have a way for defining, that example “Original” exits with 1 - without all these hacky workarounds in the following examples, which lead to technically correct behaviour!
That means, my suggestion with
cobra.NoFuncis actually not a good idea, better would berootCmd = cobra.Command{..., ExitErrorOnMissingSubcommand: true, ...}or something like thatOr actually changing the behaviour and exit 1 on usage error always and note that as breaking change for a new major release branch
While writing this up, checking some of the current tooling for their behaviour, I realized
githas only 1 command level (e.g.git log)iphas 2 levels, but if only provided the first level (e.g.ip netns), it automatically meanslistof the 2nd levelkubectlerrors 1 if there are missing subcommands (e.g.kubectl get), but they have overridden anyway all possible aspects of cobralxcerrors 0 (e.g.lxc profile), but they also use cobra so “suffering” from the exactly this topic hereopenstackpython client errors 2 (e.g.openstack server) - the first real-world example I’ve found without go or cobra