canopy-network/canopy · error
unable to marshal any payload type %s to json
Error message
unable to marshal any payload type %s to json
What it means
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'.
Source
Thrown at lib/codec.go:45
if err := proto.Unmarshal(any.Value, dynamic); err == nil {
jsonBytes, e := protojson.MarshalOptions{}.Marshal(dynamic)
if e == nil {
return jsonBytes, nil
}
}
}
// fallback to standard anypb.UnmarshalNew()
payload, payloadErr := FromAny(any)
if payloadErr == nil {
if msgI, ok := payload.(MessageI); ok {
msg, err := MarshalJSON(msgI)
if err == nil {
return msg, nil
}
}
}
// exit
return nil, fmt.Errorf("unable to marshal any payload type %s to json", any.TypeUrl)
}
// MarshalAnyProtoJSON() converts an 'any proto' into JSON
func MarshalAnyProtoJSON(any *anypb.Any) (json.RawMessage, error) {
if any == nil {
return nil, nil
}
jsonBytes, err := protojson.MarshalOptions{}.Marshal(any)
if err != nil {
return nil, ErrJSONMarshal(err)
}
return jsonBytes, nil
}
// AnyFromProtoJSON() converts JSON into a protobuf.Any
func AnyFromProtoJSON(msg json.RawMessage) (a *anypb.Any, e ErrorI) {
if len(msg) == 0 {
return nil, ErrJSONUnmarshal(fmt.Errorf("empty json payload"))View on GitHub (pinned to ee8197d91d)
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
Example fix
// before
any := &anypb.Any{TypeUrl: "type.googleapis.com/custom.v1.MyParam", ...} // never registered
// after
RegisterType(&customv1.MyParam{}) // or use a registered wrapper like StringWrapper Defensive patterns
Strategy: validation
Validate before calling
if !codec.IsRegisteredType(any.TypeUrl) {
return fmt.Errorf("type %s not registered", any.TypeUrl)
} Try / catch
jsonRaw, err := lib.MarshalAnypbJSON(any)
if err != nil {
// fall back to raw base64 of any.Value or reject the message
} Prevention
- Register every proto message type used in Any payloads
- Avoid type skew: upgrade all nodes together
- Verify TypeUrl strings against the registry in CI
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
AI-assisted analysis of canopy-network/canopy@ee8197d91d (2026-09-06).
Data as JSON: /api/errors/8bb4241d5f9c22ad.
Report an issue: GitHub.