]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/json/v2: document context annotation with SemanticError
authorJoe Tsai <joetsai@digital-static.net>
Tue, 9 Sep 2025 00:33:47 +0000 (17:33 -0700)
committerJoseph Tsai <joetsai@digital-static.net>
Wed, 10 Sep 2025 07:58:35 +0000 (00:58 -0700)
When the json package calls
Marshaler, MarshalerTo, Unmarshaler, or UnmarshalerFrom methods
and a SemanticError is returned, it will automatically
annotate the error with context.

Document this behavior.

Change-Id: Id8e775a7c1c2a6ffc29ea518913591915e8aff87
Reviewed-on: https://go-review.googlesource.com/c/go/+/701956
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/encoding/json/v2/arshal_methods.go
src/encoding/json/v2/errors.go
src/encoding/json/v2/example_orderedobject_test.go

index 664c3927cc3225f79a37fe87083c73ed1a9577fb..2decd144dbeaf9651dd02afaa30e677768ea7cb4 100644 (file)
@@ -41,6 +41,10 @@ var (
 //
 // It is recommended that implementations return a buffer that is safe
 // for the caller to retain and potentially mutate.
+//
+// If the returned error is a [SemanticError], then unpopulated fields
+// of the error may be populated by [json] with additional context.
+// Errors of other types are wrapped within a [SemanticError].
 type Marshaler interface {
        MarshalJSON() ([]byte, error)
 }
@@ -54,6 +58,11 @@ type Marshaler interface {
 //
 // The implementation must write only one JSON value to the Encoder and
 // must not retain the pointer to [jsontext.Encoder].
+//
+// If the returned error is a [SemanticError], then unpopulated fields
+// of the error may be populated by [json] with additional context.
+// Errors of other types are wrapped within a [SemanticError],
+// unless it is an IO error.
 type MarshalerTo interface {
        MarshalJSONTo(*jsontext.Encoder) error
 
@@ -72,6 +81,10 @@ type MarshalerTo interface {
 // unmarshaling into a pre-populated value.
 //
 // Implementations must not retain or mutate the input []byte.
+//
+// If the returned error is a [SemanticError], then unpopulated fields
+// of the error may be populated by [json] with additional context.
+// Errors of other types are wrapped within a [SemanticError].
 type Unmarshaler interface {
        UnmarshalJSON([]byte) error
 }
@@ -88,6 +101,11 @@ type Unmarshaler interface {
 // unmarshaling into a pre-populated value.
 //
 // Implementations must not retain the pointer to [jsontext.Decoder].
+//
+// If the returned error is a [SemanticError], then unpopulated fields
+// of the error may be populated by [json] with additional context.
+// Errors of other types are wrapped within a [SemanticError],
+// unless it is a [jsontext.SyntacticError] or an IO error.
 type UnmarshalerFrom interface {
        UnmarshalJSONFrom(*jsontext.Decoder) error
 
index 940b720210eee6900cdbdefa2c9293851998a11f..9485d7b527793cc875770dc36d74b886afa042fc 100644 (file)
@@ -62,6 +62,11 @@ func isFatalError(err error, flags jsonflags.Flags) bool {
 // SemanticError describes an error determining the meaning
 // of JSON data as Go data or vice-versa.
 //
+// If a [Marshaler], [MarshalerTo], [Unmarshaler], or [UnmarshalerFrom] method
+// returns a SemanticError when called by the [json] package,
+// then the ByteOffset, JSONPointer, and GoType fields are automatically
+// populated by the calling context if they are the zero value.
+//
 // The contents of this error as produced by this package may change over time.
 type SemanticError struct {
        requireKeyedLiterals
index d68782f72520134e28b13a53c386cef5b35ee78d..fc231325040190a4dc892e3eb0bc75db9e1bddb8 100644 (file)
@@ -53,7 +53,9 @@ func (obj *OrderedObject[V]) MarshalJSONTo(enc *jsontext.Encoder) error {
 // UnmarshalJSONFrom decodes a JSON object from dec into obj.
 func (obj *OrderedObject[V]) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
        if k := dec.PeekKind(); k != '{' {
-               return fmt.Errorf("expected object start, but encountered %v", k)
+               // The [json] package automatically populates relevant fields
+               // in a [json.SemanticError] to provide additional context.
+               return &json.SemanticError{JSONKind: k}
        }
        if _, err := dec.ReadToken(); err != nil {
                return err