Repository navigation
Description
My urfave/cli version is
Reproduced on the latest release, v3.14.0, and current main at 26bd9a2.
Checklist
- Reproduced on the latest v3 release.
- Checked the v3 manual and the Value/GenericFlag interfaces.
- Searched existing issues and PRs for GenericFlag, Getter and validator failures.
Dependency Management
Go modules.
Describe the bug
A GenericFlag can accept a value from Go's standard flag package, then panic before calling its Validator. The value satisfies cli.Value, but its Get method returns a string. GenericFlag unwraps that string and then tries to assert it back to cli.Value.
To reproduce
Save this as main.go:
package main
import (
"context"
"flag"
cli "github.com/urfave/cli/v3"
)
func main() {
std := flag.NewFlagSet("std", flag.ContinueOnError)
std.String("value", "", "")
cmd := &cli.Command{
Flags: []cli.Flag{&cli.GenericFlag{
Name: "value",
Value: std.Lookup("value").Value.(cli.Value),
Validator: func(cli.Value) error { return nil },
}},
}
_ = cmd.Run(context.Background(), []string{"app", "--value", "hello"})
}Run in an empty directory:
go mod init example.com/cli-getter-repro
go get github.com/urfave/cli/[email protected]
go run .Observed behavior
panic: interface conversion: string is not cli.Value: missing method Get
The panic occurs at the typed Validator call in FlagBase.Set. The Validator body is never reached.
On current main, I also checked these related paths with the standard-library value and a custom string Getter:
- ValidateDefaults and the flag Action panic with the same type mismatch.
- Without callbacks, parsing succeeds, but Command.Generic returns nil for the registered name and alias.
- A control Getter that returns itself works in all four cases.
Expected behavior
A value satisfying cli.Value should work with the declared cli.Value callbacks without an internal type-assertion panic. Command.Generic should be able to retrieve the registered value after successful parsing.
Additional context
cli.Value embeds flag.Getter, whose Get result can be the underlying value. The generic adapter returns that payload, but FlagBase.Set expects cli.Value for this flag type. The existing Parser test fixture returns itself from Get, which hides the mismatch.
Returning the supplied value directly from the adapter would fix these paths, but it would also change what GenericFlag.Get and Command.Value return. That could affect existing callers.
Should callbacks and Command.Generic receive the supplied cli.Value while Command.Value keeps returning its Get result, or should GenericFlag.Get consistently expose the supplied value object?
Want to fix this yourself?
Yes. I can add the regression tests and work on a fix once the intended retrieval behavior is clear.
Go version and relevant environment
go version go1.26.5 darwin/arm64
GOOS=darwin
GOARCH=arm64
The examples were run locally on both versions above; no fix has been submitted yet.
Activity
coilysiren commentedon Oct 7, 2026
@MohammediYunus this makes sense! Submit a PR at will
dearchap commentedon Oct 7, 2026
@MohammediYunus Actually I'm not sure what you are trying to do here. You can trying to use the flag.Value from the std library as a cli.Value for urfave/cli. That wont work.
MohammediYunus commentedon Oct 7, 2026
Thanks @coilysiren!
@dearchap, I should have made the distinction clearer. A flag.Value alone isn't enough. The value in that example also implements flag.Getter, so the cli.Value assertion succeeds. The panic happens later in FlagBase.Set.
Here's the same case with a custom type, without the standard flag package or a runtime type assertion:
I ran this on v3.14.0 and main at 26bd9a2. Both panic before entering the validator. Changing only Get to return v makes both pass.
Is Get expected to return a cli.Value, such as the value itself, rather than its underlying payload? If that's the intended contract, I'm happy to update the report and scope the PR accordingly. I want to avoid changing Command.Value's existing behaviour unnecessarily.
coilysiren commentedon Oct 7, 2026
My impression is that you're satisfying the interface but the validator is rejecting it a few steps down, so the solve is to either tighten the interface or loosen the validator. Im not opinionated on which one is better.
(on a train so skimming, this might not be a fully correct read)
MohammediYunus commentedon Oct 7, 2026
Thanks for taking a look! I’ve opened #2460 with a fix that keeps the existing interface and Command.Value behaviour. It handles payload-returning Getters in validation, flag actions and Command.Generic, with regression tests for each. Happy to adjust after review.