{"record":{"id":"8bb4241d5f9c22ad","repo":"canopy-network/canopy","slug":"unable-to-marshal-any-payload-type-s-to-json","errorCode":null,"errorMessage":"unable to marshal any payload type %s to json","messagePattern":"unable to marshal any payload type (.+?) to json","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/codec.go","lineNumber":45,"sourceCode":"\t\tif err := proto.Unmarshal(any.Value, dynamic); err == nil {\n\t\t\tjsonBytes, e := protojson.MarshalOptions{}.Marshal(dynamic)\n\t\t\tif e == nil {\n\t\t\t\treturn jsonBytes, nil\n\t\t\t}\n\t\t}\n\t}\n\t// fallback to standard anypb.UnmarshalNew()\n\tpayload, payloadErr := FromAny(any)\n\tif payloadErr == nil {\n\t\tif msgI, ok := payload.(MessageI); ok {\n\t\t\tmsg, err := MarshalJSON(msgI)\n\t\t\tif err == nil {\n\t\t\t\treturn msg, nil\n\t\t\t}\n\t\t}\n\t}\n\t// exit\n\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\"))","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/canopy-network/canopy/blob/ee8197d91dd410f6592cb650a94c925ee6dc8bad/lib/codec.go#L27-L63","documentation":"MarshalAnypbJSON resolves a protobuf Any's TypeUrl against a registry of known message types and marshals the inner message to JSON. If the payload type cannot be resolved or marshaled after exhausting the registry, it returns 'unable to marshal any payload type %s to json'.","triggerScenarios":"MarshalAnypbJSON is called (e.g. from MessageChangeParameter-style MarshalJSON paths) with an Any whose TypeUrl is not registered, or whose resolved message fails protojson marshaling, so the loop over candidate types exits without success.","commonSituations":"A plugin/proto message type was added but never registered in the codec's type registry; version skew where a node produces a type an older binary doesn't know; typo in the type URL.","solutions":["Register the missing message type in the codec/registry so its TypeUrl resolves","Verify the Any's TypeUrl spelling matches the registered fully-qualified proto name","Rebuild/upgrade the binary so it knows the payload type produced by the counterparty"],"exampleFix":"// before\nany := &anypb.Any{TypeUrl: \"type.googleapis.com/custom.v1.MyParam\", ...} // never registered\n// after\nRegisterType(&customv1.MyParam{}) // or use a registered wrapper like StringWrapper","handlingStrategy":"validation","validationCode":"if !codec.IsRegisteredType(any.TypeUrl) {\n    return fmt.Errorf(\"type %s not registered\", any.TypeUrl)\n}","typeGuard":null,"tryCatchPattern":"jsonRaw, err := lib.MarshalAnypbJSON(any)\nif err != nil {\n    // fall back to raw base64 of any.Value or reject the message\n}","preventionTips":["Register every proto message type used in Any payloads","Avoid type skew: upgrade all nodes together","Verify TypeUrl strings against the registry in CI"],"tags":["json","protobuf-any","registry","marshaling"],"backgroundTag":"json-marshal-failed","analyzedSha":"ee8197d91dd410f6592cb650a94c925ee6dc8bad","analyzedAt":"2026-09-06T09:30:15.973Z","contentChangedAt":"2026-09-06T09:30:15.973Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}