Skip to content

DefaultCommand don't work correctly with Flags #2249

@louisroyer

Description

@louisroyer

My urfave/cli version is

v3.6.1

Checklist

  • Are you running the latest v3 release? The list of releases is here.
  • Did you check the manual for your release? The v3 manual is here
  • Did you perform a search about this problem? Here's the GitHub guide about searching.

Dependency Management

  • My project is using go modules.

Describe the bug

When you use DefaultCommand, flags are parsed by the parent command instead of the default command. This makes DefaultCommand ususable as soon as the called command expects flags.

To reproduce

package main

import (
        "context"
        "fmt"
        "log"
        "os"

        "github.com/urfave/cli/v3"
)

func main() {
        cmd := &cli.Command{
                DefaultCommand: "run1",
                Commands: []*cli.Command{
                        {
                                Name:  "run1",
                                Usage: "run the main application",
                                Action: func(ctx context.Context, cmd *cli.Command) error {
                                        fmt.Println("Hello world from run1:", cmd.String("foo"))
                                        return nil
                                },
                                Flags: []cli.Flag{
                                        &cli.StringFlag{
                                                Name:     "foo",
                                                Required: true,
                                        },
                                },
                        },
                        {
                                Name:  "run2",
                                Usage: "run the main application",
                                Action: func(ctx context.Context, cmd *cli.Command) error {
                                        fmt.Println("Hello world from run2:", cmd.String("bar"))
                                        return nil
                                },
                                Flags: []cli.Flag{
                                        &cli.StringFlag{
                                                Name:     "bar",
                                                Required: true,
                                        },
                                },
                        },
                },
        }

        if err := cmd.Run(context.Background(), os.Args); err != nil {
                log.Fatal(err)
        }
}

Observed behavior

$ go run . --foo foo
Incorrect Usage: flag provided but not defined: -foo

NAME:
   reqflag - A new cli application

USAGE:
   reqflag [global options] [command [command options]]

COMMANDS:
   run1     run the main application
   run2     run the main application
   help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h  show help
2026/01/16 16:19:59 flag provided but not defined: -foo
exit status 1
$ go run . run1 --foo foo
Hello world from run1: foo
$ go run . run2 --bar bar
Hello world from run2: bar

Expected behavior

$ go run . --foo foo
Hello world from run1: foo
$ go run . run1 --foo foo
Hello world from run1: foo
$ go run . run2 --bar bar
Hello world from run2: bar

Additional context

Add any other context about the problem here.

If the issue relates to a specific open source GitHub repo, please
link that repo here.

If you can reproduce this issue with a public CI system, please
link a failing build here.

Want to fix this yourself?

We'd love to have more contributors on this project! If the fix for
this bug is easily explained and very small, feel free to create a
pull request for it.

Run go version and paste its output here

go version go1.25.5 linux/amd64

Run go env and paste its output here

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/louis/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/louis/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build360663747=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/louis/Téléchargements/tcli/go.mod'
GOMODCACHE='/home/louis/.local/share/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/louis/.local/share/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/louis/.local/share/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.25.5.linux-amd64'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/louis/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/louis/.local/share/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.25.5.linux-amd64/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.25.5'
GOWORK=''
PKG_CONFIG='pkg-config'

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/v3relates to / is being considered for v3kind/bugdescribes or fixes a bugstatus/triagemaintainers still need to look into this

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions