Preflight Checklist

  • [x] I have searched the issue tracker for an issue that matches the one I want to file, without success.
  • [x] I am not looking for support or already pursued the available support channels without success.
  • [x] I have checked the troubleshooting guide for my problem, without success.

Viper Version

1.20

Go Version

1.24.1

Config Source

Environment variables

Format

Other (specify below)

Repl.it link

https://replit.com/@jameel4/Viper-Struct-Unmarshaling?v=1

Code reproducing the issue

package main

import (
    "encoding/json"
    "fmt"
    "os"
    "reflect"
    "strings"

    "github.com/go-viper/mapstructure/v2"
    "github.com/spf13/viper"
)

func jsonStringUnmarshallerHookFunc() mapstructure.DecodeHookFuncValue {
    return func(f reflect.Value, t reflect.Value) (any, error) {
        data := f.Interface()
        if f.Kind() != reflect.String || t.Kind() == reflect.String {
            return data, nil
        }
        raw := data.(string)
        if raw != "" && json.Valid([]byte(raw)) {
            var m any
            err := json.Unmarshal([]byte(raw), &m)
            return m, err
        }
        return data, nil
    }
}

type Config struct {
    Foo    string
    Nested struct {
        Bar string
    }
}

func main() {
    os.Setenv("FOO", "test")
    os.Setenv("NESTED", `{"bar": "test2"}`)

    var config Config
    v := viper.NewWithOptions(
        viper.ExperimentalBindStruct(),
        viper.WithDecodeHook(jsonStringUnmarshallerHookFunc()),
    )
    v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
    v.AutomaticEnv()

    if err := v.Unmarshal(&config); err != nil {
        fmt.Println("Unable to unmarshal config")
    }
    fmt.Printf("%+v\n", config)

    if err := v.UnmarshalKey("nested", &config.Nested); err != nil {
        fmt.Println("Unable to unmarshal config")
    }
    fmt.Printf("%+v\n", config)
}

Expected Behavior

I expect the initial call to Unmarshal to correctly decode the NESTED environment variable into the Nested struct.

{Foo:test Nested:{Bar:test2}}
{Foo:test Nested:{Bar:test2}}

Actual Behavior

The NESTED environment variable in not decoded when calling Unmarshal, but it properly decoded when calling UnmarshalKey.

{Foo:test Nested:{Bar:}}
{Foo:test Nested:{Bar:test2}}

Steps To Reproduce

No response

Additional Information

No response

Comment From: github-actions[bot]

Issues with no activity for 30 days are marked stale and subject to being closed.