Viper: BindPFlag doesn't work

Created on 17 Dec 2016  路  6Comments  路  Source: spf13/viper

Hi, I'm using Viper with Cobra.
Firstly, this is my configuration file at /home/hiendv/.app.json.

{
    "host": "0.0.0.0"
}

Secondly, this is my command

var host string

// serveCmd represents the serve command
var serveCmd = &cobra.Command{
        //...
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("The host is", host)
    },
}

func init() {
        RootCmd.AddCommand(serveCmd)
    viper.BindPFlag("host", serveCmd.Flags().Lookup("host"))
    serveCmd.Flags().StringVarP(&host, "host", "H", "", "Host to listen")
}

Lastly, the result is

Using config file: /home/hiendv/.app.json
The host is 

Expected The host is 0.0.0.0

Any ideas? Thanks a lot.

Most helpful comment

For people who end up here in the future with similar issues, in @jgsqware's case, that issue can occur even with the lines in the correct order if you refer to the wrong set of flags. In the comment above, the flag is being added to PersistentFlags(), but the lookup is happening on Flags() -- you should use the same flag set in both places.

All 6 comments

Without BindPFlag, viper.GetString works just fine

func init() {
        RootCmd.AddCommand(serveCmd)
    serveCmd.Flags().StringVarP(&host, "host", "H", "", "Host to listen")
}
fmt.Println("The host is", viper.GetString("host"))
// The host is 0.0.0.0



md5-437417ba4ef5717b7bfb5229eb705f25



panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x50 pc=0x48be75]

goroutine 1 [running]:
panic(0x7f16a0, 0xc420012170)
/usr/local/go/src/runtime/panic.go:500 +0x1a1
github.com/spf13/viper.pflagValue.HasChanged(0x0, 0xc4200dfc20)
/data/go/src/github.com/spf13/viper/flags.go:41 +0x5
github.com/spf13/viper.(Viper).find(0xc4200da0f0, 0x8588ec, 0x4, 0x4, 0x61)
/data/go/src/github.com/spf13/viper/viper.go:875 +0x1021
github.com/spf13/viper.(
Viper).Get(0xc4200da0f0, 0x8588ec, 0x4, 0x475ea7, 0xa31c20)
/data/go/src/github.com/spf13/viper/viper.go:588 +0x7c
github.com/spf13/viper.(*Viper).GetString(0xc4200da0f0, 0x8588ec, 0x4, 0x0, 0x0)
/data/go/src/github.com/spf13/viper/viper.go:642 +0x3f
github.com/spf13/viper.GetString(0x8588ec, 0x4, 0x2, 0xd)
/data/go/src/github.com/spf13/viper/viper.go:640 +0x41
git.cyradar.com/hiendv/app/cmd.glob..func2(0xa5c860, 0xa7f338, 0x0, 0x0)
/data/go/src/git.cyradar.com/hiendv/app/cmd/serve.go:46 +0x141
...
exit status 2
```

In

func init() {
        RootCmd.AddCommand(serveCmd)
    viper.BindPFlag("host", serveCmd.Flags().Lookup("host"))
    serveCmd.Flags().StringVarP(&host, "host", "H", "", "Host to listen")
}

try putting serveCmd.Flags().StringVarP(...) before viper.BindPFlag(). Right now, you look up a flag that you haven't even added.

I got the same here with this:

func init() {
    RootCmd.AddCommand(variablesCmd)

    variablesCmd.PersistentFlags().String("project", "", "GitLab Project")
    viper.BindPFlag("project", variablesCmd.Flags().Lookup("project"))
}

For people who end up here in the future with similar issues, in @jgsqware's case, that issue can occur even with the lines in the correct order if you refer to the wrong set of flags. In the comment above, the flag is being added to PersistentFlags(), but the lookup is happening on Flags() -- you should use the same flag set in both places.

You get almost the same error when you accidentally lookup with the wrong command. These both may be a similar fix.

Example of broken code.

func init() {
    RootCmd.AddCommand(variablesCmd)

    variablesCmd.PersistentFlags().String("project", "", "GitLab Project")
    viper.BindPFlag("project", RootCmd.PersistentFlags().Lookup("project"))
}

Here is the trace.

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x50 pc=0x7766d5]

goroutine 1 [running]:
github.com/spf13/viper.pflagValue.HasChanged(0x0, 0xc42007f5f0)
    /home/thughes/go/src/github.com/spf13/viper/flags.go:41 +0x5
github.com/spf13/viper.(*Viper).find(0xc4200fa0f0, 0x8774e1, 0x8, 0x8, 0xc4200001a8)
    /home/thughes/go/src/github.com/spf13/viper/viper.go:893 +0xe0b
github.com/spf13/viper.(*Viper).Get(0xc4200fa0f0, 0x8774e1, 0x8, 0xc420082120, 0xc42010da10)
    /home/thughes/go/src/github.com/spf13/viper/viper.go:594 +0x7c
github.com/spf13/viper.(*Viper).GetString(0xc4200fa0f0, 0x8774e1, 0x8, 0x0, 0x0)
    /home/thughes/go/src/github.com/spf13/viper/viper.go:649 +0x3f
github.com/spf13/viper.GetString(0x8774e1, 0x8, 0x1, 0x2)
    /home/thughes/go/src/github.com/spf13/viper/viper.go:647 +0x41
git.timhughes.org/go/digger/agent.NewAgent(0x4, 0x791f10, 0xc42010dcf0)
    /home/thughes/go/src/git.timhughes.org/go/digger/agent/agent.go:24 +0x95
git.timhughes.org/go/digger/cmd.glob..func1(0xac7b60, 0xaeea38, 0x0, 0x0)
    /home/thughes/go/src/git.timhughes.org/go/digger/cmd/agent.go:22 +0x26
github.com/spf13/cobra.(*Command).execute(0xac7b60, 0xaeea38, 0x0, 0x0, 0xac7b60, 0xaeea38)
    /home/thughes/go/src/github.com/spf13/cobra/command.go:704 +0x2c6
github.com/spf13/cobra.(*Command).ExecuteC(0xac7d80, 0xac7fa0, 0x79b09c, 0xac7ec0)
    /home/thughes/go/src/github.com/spf13/cobra/command.go:785 +0x30e
github.com/spf13/cobra.(*Command).Execute(0xac7d80, 0x0, 0xc42010df48)
    /home/thughes/go/src/github.com/spf13/cobra/command.go:738 +0x2b
git.timhughes.org/go/digger/cmd.Execute()
    /home/thughes/go/src/git.timhughes.org/go/digger/cmd/root.go:27 +0x31
main.main()
    /home/thughes/go/src/git.timhughes.org/go/digger/main.go:15 +0x20
exit status 2

For people who end up here in the future with similar issues, in @jgsqware's case, that issue can occur even with the lines in the correct order if you refer to the wrong set of flags. In the comment above, the flag is being added to PersistentFlags(), but the lookup is happening on Flags() -- you should use the same flag set in both places.

Just an example of what he is saying :

This may or may not crash.

rootCmd.PersistentFlags().StringVar(&configFile, "config", "", "config file location (default is $HOME/.webhook)")
viper.BindPFlag("config", rootCmd.Flags().Lookup("config"))
//                                ^^^^^^^
// Notice how Flags is used here

This work correctly.

rootCmd.PersistentFlags().StringVar(&configFile, "config", "", "config file location (default is $HOME/.webhook)")
viper.BindPFlag("config", rootCmd.PersistentFlags().Lookup("config"))
//                                ^^^^^^^^^^^^^^^^^
// Notice how PersistentFlags is used here
Was this page helpful?
0 / 5 - 0 ratings