I'm using Viper in Golang to load configuration values from environment variables. However, I want viper.Unmarshal to return an error if a required environment variable is not set.
By default, if an environment variable is missing, viper.Unmarshal does not fail—it simply assigns the zero value to the struct field.
Here's my code:
package main
import (
"fmt"
"log"
"github.com/spf13/viper"
)
type Config struct {
DatabaseURL string `mapstructure:"DATABASE_URL"`
}
func main() {
viper.AutomaticEnv()
var config Config
if err := viper.Unmarshal(&config); err != nil {
log.Fatalf("Error unmarshaling config: %v", err)
}
fmt.Println("Config:", config)
}
If DATABASE_URL is not set, config.DatabaseURL is just an empty string instead of causing an error.
I tried using viper.BindEnv("DATABASE_URL"), but Unmarshal still does not fail when DATABASE_URL is missing.
In Viper, the Unmarshal function accepts hooks through DecoderConfigOption. Looking into viper, I found that the DecoderConfig struct has an ErrorUnset field:
// If ErrorUnset is true, then it is an error for there to exist
// fields in the result that were not set in the decoding process
// (extra fields). This only applies to decoding to a struct. This
// will affect all nested structs as well.
ErrorUnset bool
However, I’m not sure how to pass this configuration properly as a hook in Unmarshal. If anyone knows how to enable ErrorUnset using DecoderConfigOption, thank you!
How can I make viper.Unmarshal DecodeHook return an error if a required environment variable is not set?
I'm not sure if my answer is as described in your question, but you can refer to it.You can use the following code. I found that when we set ErrorUnset=true, we will check if we have set the required environment variables during unmarshal.
package main
import (
"fmt"
"log"
"github.com/go-viper/mapstructure/v2"
"github.com/spf13/viper"
)
type Config struct {
DatabaseURL string `mapstructure:"DATABASE_URL"`
}
func main() {
viper.AutomaticEnv()
var config Config
if err := viper.Unmarshal(&config, func(dc *mapstructure.DecoderConfig) {
dc.ErrorUnset = true // Set ErrorUnset field to true here
}); err != nil {
log.Fatalf("Error unmarshaling config: %v", err)
}
fmt.Println("Config:", config)
}
// output
2025/03/31 10:38:09 Error unmarshaling config: decoding failed due to the following error(s):
'' has unset fields: DATABASE_URL
exit status 1