koanf icon indicating copy to clipboard operation
koanf copied to clipboard

basicflag keymap opt does not respect key delimiter

Open JosefSchoenberger opened this issue 1 month ago • 1 comments

Describe the bug When specifying basicflag.Provider(f, "-", &basicflag.Opt{KeyMap: k}), the basicflag provider checks whether the given config key already exists in the koanf config instance, and, if so, does not overwrite it with the flag default. This, however, does not consider the delimiter argument. If, for example, the given Koanf already contains a key db.password, a flag db-password unconditionally overwrites it with the flag default, as the key db-password does not exist in the Koanf instance.

To Reproduce Create a config yaml test.yaml:

db:
  password: "test"

Then run:

k := koanf.New(".")

configPath := "./test.yaml"
if err := k.Load(file.Provider(configPath), &yaml.YAML{}); err != nil {
	log.Fatalf("Could not load config file at %v: %v", configPath, err)
}
log.Printf("%v", k.All()) // contains db.password: test

f := flag.NewFlagSet("test", flag.ExitOnError)
f.String("db-password", "default-password", "Password of database")
f.Parse(os.Args[1:])
if err := k.Load(basicflag.Provider(f, "-", &basicflag.Opt{KeyMap: k}), nil); err != nil {
	log.Fatalf("Could not set config from command line flags: %v", configPath, err)
}
log.Printf("%v", k.All()) // contains db.password: default-password, should be "test"

Additional context This seems to be related to this line: https://github.com/knadh/koanf/blob/733704a14a359ca9b3d78fead1839f7af871f8d1/providers/basicflag/basicflag.go#L126 I suppose one would need to replace all occurances of the p.delim in the key with the Koanf instance's delimiter before testing the map.

JosefSchoenberger avatar Nov 26 '25 13:11 JosefSchoenberger

This is a tricky one. Whether the default value in the flags should overwrite a previously loaded key (given that they all have the same delimiters) can be context-dependent. db.password and db-password (where - is the delimiter) both represents {"db": {"password": "..."}}

Could you not use ProviderWithValue() to get control over the key in the basicflag parser to treat it differently depending on your context?

knadh avatar Dec 01 '25 18:12 knadh