Source file src/encoding/json/v2/errors.go

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build goexperiment.jsonv2
     6  
     7  package json
     8  
     9  import (
    10  	"cmp"
    11  	"errors"
    12  	"fmt"
    13  	"io"
    14  	"reflect"
    15  	"strconv"
    16  	"strings"
    17  	"sync"
    18  
    19  	"encoding/json/internal/jsonflags"
    20  	"encoding/json/internal/jsonopts"
    21  	"encoding/json/internal/jsonwire"
    22  	"encoding/json/jsontext"
    23  )
    24  
    25  // ErrUnknownName indicates that a JSON object member could not be
    26  // unmarshaled because the name is not known to the target Go struct.
    27  // This error is directly wrapped within a [SemanticError] when produced.
    28  //
    29  // The name of an unknown JSON object member can be extracted as:
    30  //
    31  //	err := ...
    32  //	serr, ok := errors.AsType[*json.SemanticError](err)
    33  //	if ok && serr.Err == json.ErrUnknownName {
    34  //		ptr := serr.JSONPointer // JSON pointer to unknown name
    35  //		name := ptr.LastToken() // unknown name itself
    36  //		...
    37  //	}
    38  //
    39  // This error is only returned if [RejectUnknownMembers] is true.
    40  var ErrUnknownName = errors.New("unknown object member name")
    41  
    42  // errAmbiguousName indicates a JSON object member could be unmarshal
    43  // into multiple candidate Go struct fields.
    44  var errAmbiguousName = errors.New("ambiguous object member name")
    45  
    46  const errorPrefix = "json: "
    47  
    48  func isSemanticError(err error) bool {
    49  	_, ok := err.(*SemanticError)
    50  	return ok
    51  }
    52  
    53  func isSyntacticError(err error) bool {
    54  	_, ok := err.(*jsontext.SyntacticError)
    55  	return ok
    56  }
    57  
    58  // isFatalError reports whether this error must terminate arshaling.
    59  // All errors are considered fatal unless operating under
    60  // [jsonflags.ReportErrorsWithLegacySemantics] in which case only
    61  // syntactic errors and I/O errors are considered fatal.
    62  func isFatalError(err error, flags jsonflags.Flags) bool {
    63  	return !flags.Get(jsonflags.ReportErrorsWithLegacySemantics) ||
    64  		isSyntacticError(err) || export.IsIOError(err)
    65  }
    66  
    67  // SemanticError describes an error determining the meaning
    68  // of JSON data as Go data, or vice versa.
    69  //
    70  // If a [Marshaler], [MarshalerTo], [Unmarshaler], or [UnmarshalerFrom] method
    71  // returns a SemanticError when called by the [json] package,
    72  // then the ByteOffset, JSONPointer, and GoType fields are automatically
    73  // populated by the calling context if they are the zero value.
    74  //
    75  // The contents of this error as produced by this package may change over time.
    76  type SemanticError struct {
    77  	requireKeyedLiterals
    78  	nonComparable
    79  
    80  	action string // either "marshal" or "unmarshal"
    81  
    82  	// ByteOffset indicates that an error occurred at or after this byte offset.
    83  	ByteOffset int64
    84  	// JSONPointer indicates that an error occurred within this JSON value
    85  	// as indicated using the JSON Pointer notation (see RFC 6901).
    86  	JSONPointer jsontext.Pointer
    87  
    88  	// JSONKind is the JSON kind that could not be handled.
    89  	JSONKind jsontext.Kind // may be zero if unknown
    90  	// JSONValue is the JSON number or string that could not be unmarshaled.
    91  	// It is not populated during marshaling.
    92  	JSONValue jsontext.Value // may be nil if irrelevant or unknown
    93  	// GoType is the Go type that could not be handled.
    94  	GoType reflect.Type // may be nil if unknown
    95  
    96  	// Err is the underlying error.
    97  	Err error // may be nil
    98  }
    99  
   100  // coder is implemented by [jsontext.Encoder] or [jsontext.Decoder].
   101  type coder interface {
   102  	StackPointer() jsontext.Pointer
   103  	Options() Options
   104  }
   105  
   106  // newInvalidFormatError constructs a SemanticError because
   107  // the current type t cannot handle the provided options format.
   108  // This function must be called before producing or consuming the next value.
   109  //
   110  // If [jsonflags.ReportErrorsWithLegacySemantics] is specified,
   111  // then this automatically skips the next value when unmarshaling
   112  // to ensure that the value is fully consumed.
   113  func newInvalidFormatError(c coder, t reflect.Type) error {
   114  	err := fmt.Errorf("invalid format flag %q", c.Options().(*jsonopts.Struct).Format)
   115  	switch c := c.(type) {
   116  	case *jsontext.Encoder:
   117  		err = newMarshalErrorBefore(c, t, err)
   118  	case *jsontext.Decoder:
   119  		err = newUnmarshalErrorBeforeWithSkipping(c, t, err)
   120  	}
   121  	return err
   122  }
   123  
   124  // newMarshalErrorBefore wraps err in a SemanticError assuming that e
   125  // is positioned right before the next token or value, which causes an error.
   126  func newMarshalErrorBefore(e *jsontext.Encoder, t reflect.Type, err error) error {
   127  	return &SemanticError{action: "marshal", GoType: t, Err: toUnexpectedEOF(err),
   128  		ByteOffset:  e.OutputOffset() + int64(export.Encoder(e).CountNextDelimWhitespace()),
   129  		JSONPointer: jsontext.Pointer(export.Encoder(e).AppendStackPointer(nil, +1))}
   130  }
   131  
   132  // newUnmarshalErrorBefore wraps err in a SemanticError assuming that d
   133  // is positioned right before the next token or value, which causes an error.
   134  // It does not record the next JSON kind as this error is used to indicate
   135  // the receiving Go value is invalid to unmarshal into (and not a JSON error).
   136  // However, if [jsonflags.ReportErrorsWithLegacySemantics] is specified,
   137  // then it does record the next JSON kind for historical reporting reasons.
   138  func newUnmarshalErrorBefore(d *jsontext.Decoder, t reflect.Type, err error) error {
   139  	var k jsontext.Kind
   140  	if export.Decoder(d).Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
   141  		k = d.PeekKind()
   142  	}
   143  	return &SemanticError{action: "unmarshal", GoType: t, Err: toUnexpectedEOF(err),
   144  		ByteOffset:  d.InputOffset() + int64(export.Decoder(d).CountNextDelimWhitespace()),
   145  		JSONPointer: jsontext.Pointer(export.Decoder(d).AppendStackPointer(nil, +1)),
   146  		JSONKind:    k}
   147  }
   148  
   149  // newUnmarshalErrorBeforeWithSkipping is like [newUnmarshalErrorBefore],
   150  // but automatically skips the next value if
   151  // [jsonflags.ReportErrorsWithLegacySemantics] is specified.
   152  func newUnmarshalErrorBeforeWithSkipping(d *jsontext.Decoder, t reflect.Type, err error) error {
   153  	err = newUnmarshalErrorBefore(d, t, err)
   154  	if export.Decoder(d).Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
   155  		if err2 := export.Decoder(d).SkipValue(); err2 != nil {
   156  			return err2
   157  		}
   158  	}
   159  	return err
   160  }
   161  
   162  // newUnmarshalErrorAfter wraps err in a SemanticError assuming that d
   163  // is positioned right after the previous token or value, which caused an error.
   164  func newUnmarshalErrorAfter(d *jsontext.Decoder, t reflect.Type, err error) error {
   165  	tokOrVal := export.Decoder(d).PreviousTokenOrValue()
   166  	byteOffset := d.InputOffset() - int64(len(tokOrVal))
   167  	if export.Decoder(d).Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
   168  		// NOTE: In v1, the offset pointed to the end of the bad token or value.
   169  		if k := jsontext.Value(tokOrVal).Kind(); k == '[' || k == '{' {
   170  			byteOffset++ // add just the '[' or '{'
   171  		} else {
   172  			byteOffset += int64(len(tokOrVal))
   173  		}
   174  	}
   175  	return &SemanticError{action: "unmarshal", GoType: t, Err: toUnexpectedEOF(err),
   176  		ByteOffset:  byteOffset,
   177  		JSONPointer: jsontext.Pointer(export.Decoder(d).AppendStackPointer(nil, -1)),
   178  		JSONKind:    jsontext.Value(tokOrVal).Kind()}
   179  }
   180  
   181  // newUnmarshalErrorAfterWithValue wraps err in a SemanticError assuming that d
   182  // is positioned right after the previous token or value, which caused an error.
   183  // It also stores a copy of the last JSON value if it is a string or number.
   184  func newUnmarshalErrorAfterWithValue(d *jsontext.Decoder, t reflect.Type, err error) error {
   185  	serr := newUnmarshalErrorAfter(d, t, err).(*SemanticError)
   186  	if serr.JSONKind == '"' || serr.JSONKind == '0' {
   187  		serr.JSONValue = jsontext.Value(export.Decoder(d).PreviousTokenOrValue()).Clone()
   188  	}
   189  	return serr
   190  }
   191  
   192  // newUnmarshalErrorAfterWithSkipping is like [newUnmarshalErrorAfter],
   193  // but automatically skips the remainder of the current value if
   194  // [jsonflags.ReportErrorsWithLegacySemantics] is specified.
   195  func newUnmarshalErrorAfterWithSkipping(d *jsontext.Decoder, t reflect.Type, err error) error {
   196  	err = newUnmarshalErrorAfter(d, t, err)
   197  	if export.Decoder(d).Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
   198  		if err2 := export.Decoder(d).SkipValueRemainder(); err2 != nil {
   199  			return err2
   200  		}
   201  	}
   202  	return err
   203  }
   204  
   205  // newSemanticErrorWithPosition wraps err in a SemanticError assuming that
   206  // the error occurred at the provided depth, and length.
   207  // If err is already a SemanticError, then position information is only
   208  // injected if it is currently unpopulated.
   209  //
   210  // If the position is unpopulated, it is ambiguous where the error occurred
   211  // in the user code, whether it was before or after the current position.
   212  // For the byte offset, we assume that the error occurred before the last read
   213  // token or value when decoding, or before the next value when encoding.
   214  // For the JSON pointer, we point to the parent object or array unless
   215  // we can be certain that it happened with an object member.
   216  //
   217  // This is used to annotate errors returned by user-provided
   218  // v2 MarshalJSON or UnmarshalJSON methods or functions.
   219  func newSemanticErrorWithPosition(c coder, t reflect.Type, prevDepth int, prevLength int64, err error) error {
   220  	serr, _ := err.(*SemanticError)
   221  	if serr == nil {
   222  		serr = &SemanticError{Err: err}
   223  	}
   224  	serr.Err = toUnexpectedEOF(serr.Err)
   225  	var currDepth int
   226  	var currLength int64
   227  	var coderState interface{ AppendStackPointer([]byte, int) []byte }
   228  	var offset int64
   229  	switch c := c.(type) {
   230  	case *jsontext.Encoder:
   231  		e := export.Encoder(c)
   232  		serr.action = cmp.Or(serr.action, "marshal")
   233  		currDepth, currLength = e.Tokens.DepthLength()
   234  		offset = c.OutputOffset() + int64(export.Encoder(c).CountNextDelimWhitespace())
   235  		coderState = e
   236  	case *jsontext.Decoder:
   237  		d := export.Decoder(c)
   238  		serr.action = cmp.Or(serr.action, "unmarshal")
   239  		currDepth, currLength = d.Tokens.DepthLength()
   240  		tokOrVal := d.PreviousTokenOrValue()
   241  		offset = c.InputOffset() - int64(len(tokOrVal))
   242  		if (prevDepth == currDepth && prevLength == currLength) || len(tokOrVal) == 0 {
   243  			// If no Read method was called in the user-defined method or
   244  			// if the Peek method was called, then use the offset of the next value.
   245  			offset = c.InputOffset() + int64(export.Decoder(c).CountNextDelimWhitespace())
   246  		}
   247  		coderState = d
   248  	}
   249  	serr.ByteOffset = cmp.Or(serr.ByteOffset, offset)
   250  	if serr.JSONPointer == "" {
   251  		where := 0 // default to ambiguous positioning
   252  		switch {
   253  		case prevDepth == currDepth && prevLength+0 == currLength:
   254  			where = +1
   255  		case prevDepth == currDepth && prevLength+1 == currLength:
   256  			where = -1
   257  		}
   258  		serr.JSONPointer = jsontext.Pointer(coderState.AppendStackPointer(nil, where))
   259  	}
   260  	serr.GoType = cmp.Or(serr.GoType, t)
   261  	return serr
   262  }
   263  
   264  // collapseSemanticErrors collapses double SemanticErrors at the outer levels
   265  // into a single SemanticError by preserving the inner error,
   266  // but prepending the ByteOffset and JSONPointer with the outer error.
   267  //
   268  // For example:
   269  //
   270  //	collapseSemanticErrors(&SemanticError{
   271  //		ByteOffset:  len64(`[0,{"alpha":[0,1,`),
   272  //		JSONPointer: "/1/alpha/2",
   273  //		GoType:      reflect.TypeFor[outerType](),
   274  //		Err: &SemanticError{
   275  //			ByteOffset:  len64(`{"foo":"bar","fizz":[0,`),
   276  //			JSONPointer: "/fizz/1",
   277  //			GoType:      reflect.TypeFor[innerType](),
   278  //			Err:         ...,
   279  //		},
   280  //	})
   281  //
   282  // results in:
   283  //
   284  //	&SemanticError{
   285  //		ByteOffset:  len64(`[0,{"alpha":[0,1,`) + len64(`{"foo":"bar","fizz":[0,`),
   286  //		JSONPointer: "/1/alpha/2" + "/fizz/1",
   287  //		GoType:      reflect.TypeFor[innerType](),
   288  //		Err:         ...,
   289  //	}
   290  //
   291  // This is used to annotate errors returned by user-provided
   292  // v1 MarshalJSON or UnmarshalJSON methods with precise position information
   293  // if they themselves happened to return a SemanticError.
   294  // Since MarshalJSON and UnmarshalJSON are not operating on the root JSON value,
   295  // their positioning must be relative to the nested JSON value
   296  // returned by UnmarshalJSON or passed to MarshalJSON.
   297  // Therefore, we can construct an absolute position by concatenating
   298  // the outer with the inner positions.
   299  //
   300  // Note that we do not use collapseSemanticErrors with user-provided functions
   301  // that take in an [jsontext.Encoder] or [jsontext.Decoder] since they contain
   302  // methods to report position relative to the root JSON value.
   303  // We assume user-constructed errors are correctly precise about position.
   304  func collapseSemanticErrors(err error) error {
   305  	if serr1, ok := err.(*SemanticError); ok {
   306  		if serr2, ok := serr1.Err.(*SemanticError); ok {
   307  			serr2.ByteOffset = serr1.ByteOffset + serr2.ByteOffset
   308  			serr2.JSONPointer = serr1.JSONPointer + serr2.JSONPointer
   309  			*serr1 = *serr2
   310  		}
   311  	}
   312  	return err
   313  }
   314  
   315  func wrapErrUnsupported(err error, what string) error {
   316  	if errors.Is(err, errors.ErrUnsupported) {
   317  		return errors.New(what + " may not return errors.ErrUnsupported")
   318  	}
   319  	return err
   320  }
   321  
   322  // errorModalVerb is a modal verb like "cannot" or "unable to".
   323  //
   324  // Once per process, Hyrum-proof the error message by deliberately
   325  // switching between equivalent renderings of the same error message.
   326  // The randomization is tied to the Hyrum-proofing already applied
   327  // on map iteration in Go.
   328  var errorModalVerb = sync.OnceValue(func() string {
   329  	for phrase := range map[string]struct{}{"cannot": {}, "unable to": {}} {
   330  		return phrase // use whichever phrase we get in the first iteration
   331  	}
   332  	return ""
   333  })
   334  
   335  func (e *SemanticError) Error() string {
   336  	var sb strings.Builder
   337  	sb.WriteString(errorPrefix)
   338  	sb.WriteString(errorModalVerb())
   339  
   340  	// Format action.
   341  	var preposition string
   342  	switch e.action {
   343  	case "marshal":
   344  		sb.WriteString(" marshal")
   345  		preposition = " from"
   346  	case "unmarshal":
   347  		sb.WriteString(" unmarshal")
   348  		preposition = " into"
   349  	default:
   350  		sb.WriteString(" handle")
   351  		preposition = " with"
   352  	}
   353  
   354  	// Format JSON kind.
   355  	switch e.JSONKind {
   356  	case 'n':
   357  		sb.WriteString(" JSON null")
   358  	case 'f', 't':
   359  		sb.WriteString(" JSON boolean")
   360  	case '"':
   361  		sb.WriteString(" JSON string")
   362  	case '0':
   363  		sb.WriteString(" JSON number")
   364  	case '{', '}':
   365  		sb.WriteString(" JSON object")
   366  	case '[', ']':
   367  		sb.WriteString(" JSON array")
   368  	default:
   369  		if e.action == "" {
   370  			preposition = ""
   371  		}
   372  	}
   373  	if len(e.JSONValue) > 0 && len(e.JSONValue) < 100 {
   374  		sb.WriteByte(' ')
   375  		sb.Write(e.JSONValue)
   376  	}
   377  
   378  	// Format Go type.
   379  	if e.GoType != nil {
   380  		typeString := e.GoType.String()
   381  		if len(typeString) > 100 {
   382  			// An excessively long type string most likely occurs for
   383  			// an anonymous struct declaration with many fields.
   384  			// Reduce the noise by just printing the kind,
   385  			// and optionally prepending it with the package name
   386  			// if the struct happens to include an unexported field.
   387  			typeString = e.GoType.Kind().String()
   388  			if e.GoType.Kind() == reflect.Struct && e.GoType.Name() == "" {
   389  				for i := range e.GoType.NumField() {
   390  					if pkgPath := e.GoType.Field(i).PkgPath; pkgPath != "" {
   391  						typeString = pkgPath[strings.LastIndexByte(pkgPath, '/')+len("/"):] + ".struct"
   392  						break
   393  					}
   394  				}
   395  			}
   396  		}
   397  		sb.WriteString(preposition)
   398  		sb.WriteString(" Go ")
   399  		sb.WriteString(typeString)
   400  	}
   401  
   402  	// Special handling for unknown names.
   403  	if e.Err == ErrUnknownName || e.Err == errAmbiguousName {
   404  		sb.WriteString(": ")
   405  		sb.WriteString(e.Err.Error())
   406  		sb.WriteString(" ")
   407  		sb.WriteString(strconv.Quote(e.JSONPointer.LastToken()))
   408  		if parent := e.JSONPointer.Parent(); parent != "" {
   409  			sb.WriteString(" within ")
   410  			sb.WriteString(strconv.Quote(jsonwire.TruncatePointer(string(parent), 100)))
   411  		}
   412  		return sb.String()
   413  	}
   414  
   415  	// Format where.
   416  	// Avoid printing if it overlaps with a wrapped SyntacticError.
   417  	switch serr, _ := e.Err.(*jsontext.SyntacticError); {
   418  	case e.JSONPointer != "":
   419  		if serr == nil || !e.JSONPointer.Contains(serr.JSONPointer) {
   420  			sb.WriteString(" within ")
   421  			sb.WriteString(strconv.Quote(jsonwire.TruncatePointer(string(e.JSONPointer), 100)))
   422  		}
   423  	case e.ByteOffset > 0:
   424  		if serr == nil || !(e.ByteOffset <= serr.ByteOffset) {
   425  			sb.WriteString(" after offset ")
   426  			sb.WriteString(strconv.FormatInt(e.ByteOffset, 10))
   427  		}
   428  	}
   429  
   430  	// Format underlying error.
   431  	if e.Err != nil {
   432  		errString := e.Err.Error()
   433  		if isSyntacticError(e.Err) {
   434  			errString = strings.TrimPrefix(errString, "jsontext: ")
   435  		}
   436  		sb.WriteString(": ")
   437  		sb.WriteString(errString)
   438  	}
   439  
   440  	return sb.String()
   441  }
   442  
   443  func (e *SemanticError) Unwrap() error {
   444  	return e.Err
   445  }
   446  
   447  func newDuplicateNameError(ptr jsontext.Pointer, quotedName []byte, offset int64) error {
   448  	if quotedName != nil {
   449  		name, _ := jsonwire.AppendUnquote(nil, quotedName)
   450  		ptr = ptr.AppendToken(string(name))
   451  	}
   452  	return &jsontext.SyntacticError{
   453  		ByteOffset:  offset,
   454  		JSONPointer: ptr,
   455  		Err:         jsontext.ErrDuplicateName,
   456  	}
   457  }
   458  
   459  // toUnexpectedEOF converts [io.EOF] to [io.ErrUnexpectedEOF].
   460  func toUnexpectedEOF(err error) error {
   461  	if err == io.EOF {
   462  		return io.ErrUnexpectedEOF
   463  	}
   464  	return err
   465  }
   466  

View as plain text