{"record":{"id":"9eb3730bb62faf44","repo":"canopy-network/canopy","slug":"errjsonunmarshal","errorCode":"ErrJSONUnmarshal","errorMessage":"empty json payload","messagePattern":"empty json payload","errorType":"error_code","errorClass":"ErrJSONUnmarshal","httpStatus":null,"severity":"error","filePath":"lib/codec.go","lineNumber":63,"sourceCode":"\treturn nil, fmt.Errorf(\"unable to marshal any payload type %s to json\", any.TypeUrl)\n}\n\n// MarshalAnyProtoJSON() converts an 'any proto' into JSON\nfunc MarshalAnyProtoJSON(any *anypb.Any) (json.RawMessage, error) {\n\tif any == nil {\n\t\treturn nil, nil\n\t}\n\tjsonBytes, err := protojson.MarshalOptions{}.Marshal(any)\n\tif err != nil {\n\t\treturn nil, ErrJSONMarshal(err)\n\t}\n\treturn jsonBytes, nil\n}\n\n// AnyFromProtoJSON() converts JSON into a protobuf.Any\nfunc AnyFromProtoJSON(msg json.RawMessage) (a *anypb.Any, e ErrorI) {\n\tif len(msg) == 0 {\n\t\treturn nil, ErrJSONUnmarshal(fmt.Errorf(\"empty json payload\"))\n\t}\n\ta = new(anypb.Any)\n\tif err := protojson.Unmarshal(msg, a); err != nil {\n\t\treturn nil, ErrJSONUnmarshal(err)\n\t}\n\treturn a, nil\n}\n\n// AnyFromJSONForMessageType() converts JSON into anypb\nfunc AnyFromJSONForMessageType(messageType string, msg json.RawMessage) (*anypb.Any, ErrorI) {\n\tif messageType == \"\" {\n\t\treturn nil, ErrUnknownMessageName(messageType)\n\t}\n\tdesc := globalPluginSchemaRegistry.FindMessageDescriptorForMessageType(messageType)\n\ttypeURL := messageType\n\tif strings.Contains(messageType, \"/\") {\n\t\tdesc = globalPluginSchemaRegistry.FindMessageDescriptorForTypeURL(messageType)\n\t} else if desc != nil {","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/canopy-network/canopy/blob/ee8197d91dd410f6592cb650a94c925ee6dc8bad/lib/codec.go#L45-L81","documentation":"Raised in AnyFromProtoJSON (lib/codec.go:63) when the input json.RawMessage is empty (len 0). There is no JSON to unmarshal into a protobuf.Any, so the conversion is rejected up front with ErrJSONUnmarshal instead of producing a nil/degenerate Any.","triggerScenarios":"AnyFromProtoJSON is called from UnmarshalJSON with an empty (zero-length) json.RawMessage — e.g. the message's parameterValue/parameter bytes were empty or the field was omitted so nothing was passed through.","commonSituations":"A client submits a tx JSON with a missing/empty parameter field; upstream marshaling produced empty raw JSON; a nil value was serialized as an empty slice.","solutions":["Ensure the JSON being unmarshaled contains a non-empty payload (check len before calling)","Fix the producer so it omits the call entirely or emits at least '{}' instead of empty bytes","Guard the caller: skip AnyFromProtoJSON when json.RawMessage is nil/empty"],"exampleFix":"// before\nvar msg json.RawMessage\na, err := lib.AnyFromProtoJSON(msg) // msg is empty\n// after\nif len(msg) == 0 {\n    return fmt.Errorf(\"missing parameter payload\")\n}\na, err := lib.AnyFromProtoJSON(msg)","handlingStrategy":"validation","validationCode":"if len(raw) == 0 {\n    return errors.New(\"refusing to unmarshal empty json payload\")\n}","typeGuard":"func nonEmptyJSON(m json.RawMessage) bool { return len(m) > 0 }","tryCatchPattern":"a, err := lib.AnyFromProtoJSON(raw)\nvar eErr *fsm.ErrorI\nif err != nil && strings.Contains(err.Error(), \"empty json payload\") {\n    // treat as missing parameter field\n}","preventionTips":["Omit the call rather than passing empty bytes","Emit '{}' or a real payload instead of empty raw JSON from producers","Validate tx JSON completeness before signing/submission"],"tags":["json","protobuf-any","empty-input","validation"],"backgroundTag":"empty-required-field","analyzedSha":"ee8197d91dd410f6592cb650a94c925ee6dc8bad","analyzedAt":"2026-09-06T09:30:15.973Z","contentChangedAt":"2026-09-06T09:30:15.973Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}