My urfave/cli version is v3.6.2
Checklist
Dependency Management
- My project is using go modules.
Describe the bug
Setting HideHelpCommand: true on a parent command causes subcommand help to use SubcommandHelpTemplate instead of CommandHelpTemplate, which results in GLOBAL OPTIONS (persistent flags from the root command) not being displayed in subcommand help output.
The root cause is in helpCommandAction() in help.go. The template selection logic at lines 125-140 depends on len(cmd.Commands):
if (len(cmd.Commands) == 1 && !cmd.HideHelp) || (len(cmd.Commands) == 0 && cmd.HideHelp) {
tmpl = CommandHelpTemplate // Has GLOBAL OPTIONS
} else {
ShowSubcommandHelp(cmd) // Uses SubcommandHelpTemplate - NO GLOBAL OPTIONS
}
When HideHelpCommand: true is set:
ensureHelp() does NOT add the internal help subcommand to cmd.Commands
- Subcommand ends up with
len(Commands) == 0
- With
HideHelp = false (default), condition evaluates to false
- Falls through to
ShowSubcommandHelp() → uses SubcommandHelpTemplate → GLOBAL OPTIONS missing
When HideHelpCommand: false (default):
ensureHelp() adds the internal help subcommand
- Subcommand ends up with
len(Commands) == 1
- Condition evaluates to
true
- Uses
CommandHelpTemplate → GLOBAL OPTIONS displayed correctly
To reproduce
package main
import (
"context"
"fmt"
"os"
"github.com/urfave/cli/v3"
)
func main() {
app := &cli.Command{
Name: "myapp",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "config",
Usage: "Path to config file",
},
},
HideHelpCommand: true, // This breaks GLOBAL OPTIONS in subcommand help
Commands: []*cli.Command{
{
Name: "serve",
Usage: "Start the server",
Action: func(ctx context.Context, c *cli.Command) error {
fmt.Println("serving...")
return nil
},
},
},
}
if err := app.Run(context.Background(), os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
Run:
go run main.go serve --help
Observed behavior
NAME:
myapp serve - Start the server
USAGE:
myapp serve
OPTIONS:
--help, -h show help
Note: GLOBAL OPTIONS section is missing - the --config flag is not shown.
Expected behavior
NAME:
myapp serve - Start the server
USAGE:
myapp serve [options]
OPTIONS:
--help, -h show help
GLOBAL OPTIONS:
--config string Path to config file
The GLOBAL OPTIONS section should be displayed regardless of whether HideHelpCommand is set, because:
HideHelpCommand is documented to hide the help subcommand, not affect help output format
CommandHelpTemplate includes {{if .VisiblePersistentFlags}}GLOBAL OPTIONS:...{{end}}
SubcommandHelpTemplate lacks this section entirely
- The choice between these templates should not depend on whether an internal help subcommand exists
Additional context
Workaround
Override cli.ShowSubcommandHelp to use CustomHelpTemplate when available:
cli.ShowSubcommandHelp = func(cmd *cli.Command) error {
tmpl := cmd.CustomHelpTemplate
if tmpl == "" {
tmpl = cli.SubcommandHelpTemplate
}
cli.HelpPrinter(cmd.Root().Writer, tmpl, cmd)
return nil
}
And set CustomHelpTemplate on commands to include the GLOBAL OPTIONS section.
Suggested fix
Either:
- Add
{{if .VisiblePersistentFlags}}GLOBAL OPTIONS:{{template "visiblePersistentFlagTemplate" .}}{{end}} to SubcommandHelpTemplate
- Or change the template selection logic in
helpCommandAction() to not depend on len(cmd.Commands) which is affected by HideHelpCommand
- Or make
DefaultShowSubcommandHelp respect CustomHelpTemplate like DefaultShowCommandHelp does
Want to fix this yourself?
Yes, I'd be happy to submit a PR. The simplest fix would be to add the GLOBAL OPTIONS section to SubcommandHelpTemplate in template.go:
var SubcommandHelpTemplate = `NAME:
{{template "helpNameTemplate" .}}
USAGE:
...existing template content...
OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .VisiblePersistentFlags}}
GLOBAL OPTIONS:{{template "visiblePersistentFlagTemplate" .}}{{end}}
`
Run go version and paste its output here
go version go1.24.4 darwin/arm64
Run go env and paste its output here
AR='ar'
CC='clang'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='clang++'
GCCGO='gccgo'
GO111MODULE='on'
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/Users/user/Library/Caches/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/Users/user/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/x2/3fr4kvl139zc880zh91n0j_c0000gp/T/go-build3762887804=/tmp/go-build -gno-record-gcc-switches -fno-common'
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMOD='/Users/user/Developer/P09580-SimulationToolkit/go.mod'
GOMODCACHE='/Users/user/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/user/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/Users/user/Developer/.anyenv/envs/goenv/versions/1.24.4'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/user/Library/Application Support/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/Users/user/Developer/.anyenv/envs/goenv/versions/1.24.4/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.24.4'
GOWORK=''
PKG_CONFIG='pkg-config'
My urfave/cli version is v3.6.2
Checklist
Dependency Management
Describe the bug
Setting
HideHelpCommand: trueon a parent command causes subcommand help to useSubcommandHelpTemplateinstead ofCommandHelpTemplate, which results inGLOBAL OPTIONS(persistent flags from the root command) not being displayed in subcommand help output.The root cause is in
helpCommandAction()inhelp.go. The template selection logic at lines 125-140 depends onlen(cmd.Commands):When
HideHelpCommand: trueis set:ensureHelp()does NOT add the internalhelpsubcommand tocmd.Commandslen(Commands) == 0HideHelp = false(default), condition evaluates tofalseShowSubcommandHelp()→ usesSubcommandHelpTemplate→ GLOBAL OPTIONS missingWhen
HideHelpCommand: false(default):ensureHelp()adds the internalhelpsubcommandlen(Commands) == 1trueCommandHelpTemplate→ GLOBAL OPTIONS displayed correctlyTo reproduce
Run:
Observed behavior
Note: GLOBAL OPTIONS section is missing - the
--configflag is not shown.Expected behavior
The
GLOBAL OPTIONSsection should be displayed regardless of whetherHideHelpCommandis set, because:HideHelpCommandis documented to hide thehelpsubcommand, not affect help output formatCommandHelpTemplateincludes{{if .VisiblePersistentFlags}}GLOBAL OPTIONS:...{{end}}SubcommandHelpTemplatelacks this section entirelyAdditional context
Workaround
Override
cli.ShowSubcommandHelpto useCustomHelpTemplatewhen available:And set
CustomHelpTemplateon commands to include the GLOBAL OPTIONS section.Suggested fix
Either:
{{if .VisiblePersistentFlags}}GLOBAL OPTIONS:{{template "visiblePersistentFlagTemplate" .}}{{end}}toSubcommandHelpTemplatehelpCommandAction()to not depend onlen(cmd.Commands)which is affected byHideHelpCommandDefaultShowSubcommandHelprespectCustomHelpTemplatelikeDefaultShowCommandHelpdoesWant to fix this yourself?
Yes, I'd be happy to submit a PR. The simplest fix would be to add the GLOBAL OPTIONS section to
SubcommandHelpTemplateintemplate.go:Run
go versionand paste its output hereRun
go envand paste its output here