From 4a559338ae69656b32ecf0364108b56d359bba5c Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Sat, 7 Feb 2026 19:52:27 +0100 Subject: [PATCH] improve JSON error message (#5412) (#5433) Co-authored-by: Zaphkiel --- internal/conf/jsonwrapper/unmarshal.go | 13 +++++-- internal/conf/jsonwrapper/unmarshal_test.go | 38 +++++++++++++++------ 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/internal/conf/jsonwrapper/unmarshal.go b/internal/conf/jsonwrapper/unmarshal.go index 31cf05f1..b66e4a0a 100644 --- a/internal/conf/jsonwrapper/unmarshal.go +++ b/internal/conf/jsonwrapper/unmarshal.go @@ -15,10 +15,13 @@ import ( // - prevents using existing elements of slices, fixing https://github.com/golang/go/issues/21092 // - prevents setting slices to nil -func process(v reflect.Value, raw any) error { +func process(v reflect.Value, raw any, path string) error { switch v.Kind() { case reflect.Slice: if raw == nil { + if path != "" { + return fmt.Errorf("cannot set slice '%s' to nil", path) + } return fmt.Errorf("cannot set slice to nil") } @@ -41,7 +44,11 @@ func process(v reflect.Value, raw any) error { jsonKey = strings.Split(jsonKey, ",")[0] if rawVal, ok2 := rawMap[jsonKey]; ok2 { - err := process(field, rawVal) + fieldPath := jsonKey + if path != "" { + fieldPath = path + "." + jsonKey + } + err := process(field, rawVal, fieldPath) if err != nil { return err } @@ -71,7 +78,7 @@ func Decode(r io.Reader, dest any) error { return err } - err = process(reflect.ValueOf(dest).Elem(), raw) + err = process(reflect.ValueOf(dest).Elem(), raw, "") if err != nil { return err } diff --git a/internal/conf/jsonwrapper/unmarshal_test.go b/internal/conf/jsonwrapper/unmarshal_test.go index 818873d9..0817153d 100644 --- a/internal/conf/jsonwrapper/unmarshal_test.go +++ b/internal/conf/jsonwrapper/unmarshal_test.go @@ -74,21 +74,37 @@ func TestUnmarshalPreventSliceReuse(t *testing.T) { } func TestUnmarshalSetSliceToNil(t *testing.T) { - type Data struct { - Items []string `json:"items"` - } + t.Run("top level", func(t *testing.T) { + type Data struct { + Items []string `json:"items"` + } - var data Data + var data Data - json := []byte(`{"items": null}`) - err := Unmarshal(json, &data) - require.EqualError(t, err, "cannot set slice to nil") + json := []byte(`{"items": null}`) + err := Unmarshal(json, &data) + require.EqualError(t, err, "cannot set slice 'items' to nil") - data = Data{Items: []string{"a", "b"}} + data = Data{Items: []string{"a", "b"}} - json = []byte(`{"items": null}`) - err = Unmarshal(json, &data) - require.EqualError(t, err, "cannot set slice to nil") + json = []byte(`{"items": null}`) + err = Unmarshal(json, &data) + require.EqualError(t, err, "cannot set slice 'items' to nil") + }) + + t.Run("nested", func(t *testing.T) { + type Inner struct { + Values []int `json:"values"` + } + type Outer struct { + Inner Inner `json:"inner"` + } + + var data Outer + json := []byte(`{"inner": {"values": null}}`) + err := Unmarshal(json, &data) + require.EqualError(t, err, "cannot set slice 'inner.values' to nil") + }) } func TestUnmarshalSetNullableSliceToNil(t *testing.T) {