Skip to content

Integer casts in posflag.FlagVal result in unexpected error #362

@n9v9

Description

@n9v9

Describe the bug

The function posflag.FlagVal uses a type switch to get a flag's value in the correct type, but then casts each signed integer to int64 and each unsigned integer to uint64.

With the following configuration, this behavior will result in an unexpected error:

  1. Use koanf.Conf.StrictMerge: true to prevent the case where e.g. a bool overwrites an int.
  2. Load the initial config via another provider, e.g. confmap that sets an int value.
  3. Use the posflag provider to map an int flag to the int config value via posflag.ProviderWithFlag. Use posflag.FlagVal to get the value.

Even though the initial config uses int and the flag is defined as an int, loading the values via the posflag provider results in the following error when koanf tries to merge both values:

incorrect types at key , type int != int64

To Reproduce

package main

import (
	"fmt"

	"github.com/knadh/koanf/providers/confmap"
	"github.com/knadh/koanf/providers/posflag"
	"github.com/knadh/koanf/v2"
	"github.com/spf13/pflag"
)

func main() {
	k := koanf.NewWithConf(koanf.Conf{
		Delim: ".",
		// Setting it to false won't trigger the bug, but it would also allow
		// overwriting a bool with an int, which I want to prevent.
		StrictMerge: true,
	})

	// Making "1" an int64 also "fixes" the issue.
	confmapProvider := confmap.Provider(map[string]any{"a": int(1)}, "")
	if err := k.Load(confmapProvider, nil); err != nil {
		panic(err)
	}

	// Output: 1 (int)
	fmt.Printf("%v (%T)\n", k.Get("a"), k.Get("a"))

	fs := pflag.NewFlagSet("", pflag.PanicOnError)
	fs.Int("a-flag", 0, "")
	if err := fs.Set("a-flag", "2"); err != nil {
		panic(err)
	}

	flagNameToConfig := map[string]string{"a-flag": "a"}
	posflagProvider := posflag.ProviderWithFlag(fs, ".", nil, func(f *pflag.Flag) (string, any) {
		posflagVal := posflag.FlagVal(fs, f)

		// Output: 2 (int64)
		fmt.Printf("%v (%T)\n", posflagVal, posflagVal)

		return flagNameToConfig[f.Name], posflagVal
	})
	if err := k.Load(posflagProvider, nil); err != nil {
		// Results in error: incorrect types at key , type int != int64
		panic(err)
	}
}

Expected behavior

I expected that posflag.FlagVal returns the value with the same type that the flag is defined with and therefore for no error to occur.

Making posflag.FlagVal assign i directly to val instead of casting it to int64/uint64 and then assigning it to val fixes the issue; but I don't know if I'm missing the reason why the casts are there.

Please provide the following information):

  • OS: linux
  • Koanf Version v2.2.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions