Skip to content

Commit 18796ad

Browse files
committed
encoding/json: merge FieldStack if the error's Field exists.
When people return UnmarshalTypeError in UnmarshalJSON, we should append error's Field to FieldStack. Fixes #68750
1 parent 18fc547 commit 18796ad

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

src/encoding/json/decode.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,11 @@ func (d *decodeState) addErrorContext(err error) error {
255255
switch err := err.(type) {
256256
case *UnmarshalTypeError:
257257
err.Struct = d.errorContext.Struct.Name()
258-
err.Field = strings.Join(d.errorContext.FieldStack, ".")
258+
fieldStack := d.errorContext.FieldStack
259+
if err.Field != "" {
260+
fieldStack = append(fieldStack, err.Field)
261+
}
262+
err.Field = strings.Join(fieldStack, ".")
259263
}
260264
}
261265
return err

src/encoding/json/decode_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,21 @@ func (*SS) UnmarshalJSON(data []byte) error {
6262
return &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[SS]()}
6363
}
6464

65+
type TAlias T
66+
67+
func (tt *TAlias) UnmarshalJSON(data []byte) error {
68+
t := T{}
69+
if err := Unmarshal(data, &t); err != nil {
70+
return err
71+
}
72+
*tt = TAlias(t)
73+
return nil
74+
}
75+
76+
type TOuter struct {
77+
T TAlias
78+
}
79+
6580
// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and
6681
// without UseNumber
6782
var ifaceNumAsFloat64 = map[string]any{
@@ -428,6 +443,7 @@ var unmarshalTests = []struct {
428443
{CaseName: Name(""), in: `{"x": 1}`, ptr: new(tx), out: tx{}},
429444
{CaseName: Name(""), in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true},
430445
{CaseName: Name(""), in: `{"S": 23}`, ptr: new(W), out: W{}, err: &UnmarshalTypeError{"number", reflect.TypeFor[SS](), 0, "W", "S"}},
446+
{CaseName: Name(""), in: `{"T": {"X": 23}}`, ptr: new(TOuter), out: TOuter{}, err: &UnmarshalTypeError{"number", reflect.TypeFor[string](), 0, "TOuter", "T.X"}},
431447
{CaseName: Name(""), in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
432448
{CaseName: Name(""), in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
433449
{CaseName: Name(""), in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(any), out: ifaceNumAsFloat64},

0 commit comments

Comments
 (0)