Unexpected nil pointer exception when implmenting Singleton

Hi everyone, thanks for your time. In the following code of mine, I had a nil pointer exception which I’m not sure why it happened:

package config

type Config struct {
	DbStr  string `mapstructure:"DB_STRING"`
	DbName string `mapstructure:"DB_NAME"`
	Port   uint32 `mapstructure:"PORT"`
}

var LoadedConfig Config
var isConfigLoaded bool

func loadConfig(path string) (err error) {
	viper.SetDefault("PORT", 3000)
	viper.AddConfigPath(path)
	viper.SetConfigName("app")
	viper.SetConfigType("env")
	viper.AutomaticEnv()

	if err = viper.ReadInConfig(); err != nil {
		return
	}

	err = viper.Unmarshal(&LoadedConfig)

	if err == nil {
		isConfigLoaded = true
	}

	return
}

func GetConfig(path string) (config *Config, err error) {
	if isConfigLoaded {
		return &LoadedConfig, nil
	}

	err = loadConfig(path)

	return
}

In the main.go file, I just run config, err := config.GetConfig(".") but then gets a panic: runtime error: invalid memory address or nil pointer dereference

I think the reason is that I tried to marshal the package-level Config variable, which is believed to be a nil(though I think it’s not nil since it’s a zero-valued variable of struct)

Interestingly, when I tried changing the loadedConfig into var configInstance *Config then it works (of course with modified code).

FYI this is the successful code after modification:

package config

var configInstance *Config

func loadConfig(path string) (err error) {
	config := Config{}
	viper.SetDefault("PORT", 3000)
	viper.AddConfigPath(path)
	viper.SetConfigName("app")
	viper.SetConfigType("env")
	viper.AutomaticEnv()

	if err = viper.ReadInConfig(); err != nil {
		return
	}

	err = viper.Unmarshal(&config)

	if err == nil {
		configInstance = &config
	}

	return
}

func GetConfig(path string) (*Config, error) {
	if configInstance != nil {
		return configInstance, nil
	}

	err := loadConfig(path)

	return configInstance, err
}

Could you please help me understand why the zeroed-value struct at package-level can’t be used for marshalling? Thank you!

You are not initializing ‘config’ named return value in GetConfig function. A return statement without arguments returns the named return values. See A Tour of Go

1 Like

Thank you! What a silly mistake of mine :smiley: