cobra: return non-zero exit code upon non-runnable subcommand

when excuting a root comand , cobra returns success on typos and exit code is 1.

➜  ~ helm notfoundsubcommand
Error: unknown command "notfoundsubcommand" for "helm"
Run 'helm --help' for usage.
➜  ~ echo $?
1

when excuting a subcommand ,cobra returns success on typos but exit code is 0.

➜  ~ helm repo sadd foo https://foo/bar

This command consists of multiple subcommands to interact with chart repositories.

It can be used to add, remove, list, and index chart repositories.

Usage:
  helm repo [command]

Available Commands:
  add         add a chart repository
....

➜  ~ echo $?
0

This issue has come up before and this is related pr.

The related helm pr is here.

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 1
  • Comments: 15 (2 by maintainers)

Commits related to this issue

Most upvoted comments

Since my issue was closed as a duplicate to this, I would like to try to raise this issue again.

I understand that changing the behavior could break backward compatibility, but is there some workaround to detect this case?

Hello. I am also running into this. The issue happens for me when a subcommand is passed an arugment it does not understand. Instead of the program exiting with non-zero, it dumps the usage string and exits with 0.

Minimal working example:

package main

import (
    "errors"
    "flag"
    "os"

    "github.com/spf13/cobra"
)

var root = &cobra.Command{
    Use: "myCmd",
}

var subCmd = &cobra.Command{
    Use: "subCmd",
}

func main() {

    root.AddCommand(subCmd)
    
    err := root.Execute()
    if err != nil {
         os.Exit(1)
    }
    os.Exit(0)
}

Then build, go build and run myCmd subCmd notAValidArg. Usage will be printed (which in this case is just an empty string) and the exit value is 0. Compare that with myCmd notAValigArg which will exit with 1.

I believe if you just return the error instead of nil, this main will exit with 1 in both cases.

https://github.com/spf13/cobra/blob/fd865a44e3c48afeb6a6dbddadb8a5519173e029/command.go#L1074

So this:

		if errors.Is(err, flag.ErrHelp) {
			cmd.HelpFunc()(cmd, args)
			return cmd, err
		}

Just propagate the error back up to the caller. I can submit this as a PR, if you’d like.

IIRC, has something to do with the legacyArgs() function is may be tricky to fix due to backwards-compatibility issue. But I agree it is poor behaviour and would be great to find a solution.