From e2f95f86610b60e1794ebd30ced9100360c03be7 Mon Sep 17 00:00:00 2001 From: wwww-deeeee <192517353+wwww-deeeee@users.noreply.github.com> Date: Thu, 17 Sep 2026 17:13:14 +0800 Subject: [PATCH] fix: do not report unset error for ignored fields when ErrorUnset is enabled (resolves #350) --- mapstructure.go | 7 ++++ mapstructure_test.go | 81 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/mapstructure.go b/mapstructure.go index 7581806a..f7c0fb82 100644 --- a/mapstructure.go +++ b/mapstructure.go @@ -1363,6 +1363,13 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e fieldName = tagValue } + if tagValue == "-" { + continue + } + if tagValue == "" && d.config.IgnoreUntaggedFields { + continue + } + rawMapKey := reflect.ValueOf(fieldName) rawMapVal := dataVal.MapIndex(rawMapKey) if !rawMapVal.IsValid() { diff --git a/mapstructure_test.go b/mapstructure_test.go index d31129d7..c8575948 100644 --- a/mapstructure_test.go +++ b/mapstructure_test.go @@ -2789,6 +2789,87 @@ func testArrayInput(t *testing.T, input map[string]interface{}, expected *Array) } func stringPtr(v string) *string { return &v } + +type BasicIgnored struct { + Vstring string `mapstructure:"-"` + Vint int +} + +func TestDecoder_ErrorUnset_IgnoredField(t *testing.T) { + input := map[string]interface{}{ + "Vint": 1, + } + + var result BasicIgnored + err := Decode(&input, &result) + if err != nil { + t.Fatalf("got an error: %s", err) + } + + if result.Vint != 1 { + t.Errorf("Vint should be 1: %d", result.Vint) + } +} + +func TestDecoder_ErrorUnset_IgnoredFieldWithConfig(t *testing.T) { + input := map[string]interface{}{ + "Vint": 1, + } + + var result BasicIgnored + config := &DecoderConfig{ + ErrorUnset: true, + Result: &result, + DecodeHook: DecodeHookFunc(func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + return data, nil + }), + } + decoder, err := NewDecoder(config) + if err != nil { + t.Fatalf("err: %s", err) + } + err = decoder.Decode(input) + if err != nil { + t.Fatalf("got an error: %s", err) + } + + if result.Vint != 1 { + t.Errorf("Vint should be 1: %d", result.Vint) + } +} + +type BasicIgnoredUntagged struct { + Vstring string + Vint int +} + +func TestDecoder_ErrorUnset_IgnoredUntaggedField(t *testing.T) { + input := map[string]interface{}{ + "Vint": 1, + } + + var result BasicIgnoredUntagged + config := &DecoderConfig{ + ErrorUnset: true, + Result: &result, + IgnoreUntaggedFields: true, + } + decoder, err := NewDecoder(config) + if err != nil { + t.Fatalf("err: %s", err) + } + err = decoder.Decode(input) + if err != nil { + t.Fatalf("got an error: %s", err) + } + + if result.Vstring != "" { + t.Errorf("Vstring should be empty: %s", result.Vstring) + } +} func intPtr(v int) *int { return &v } func uintPtr(v uint) *uint { return &v } func boolPtr(v bool) *bool { return &v }