canopy-network/canopy · error · ValueError
Message type does not support deserialization
Error message
Message type does not support deserialization
What it means
unmarshal decodes raw bytes into a protobuf message using message_type.FromString(data). If the given message_type lacks FromString (i.e. it is not a generated protobuf message class, or an instance was passed instead of the class), it raises ValueError, re-raised as an err_unmarshal-wrapped error. Callers include check_tx (decoding FeeParams) and _deliver_message_send.
Source
Thrown at plugin/python/contract/contract.py:139
def marshal(message: Any) -> bytes:
"""Marshal object to protobuf bytes."""
try:
if hasattr(message, 'SerializeToString'):
return message.SerializeToString()
raise ValueError("Message does not support serialization")
except Exception as err:
raise err_unmarshal(err)
def unmarshal(message_type: Any, data: Optional[bytes]) -> Optional[Any]:
"""Unmarshal bytes to protobuf message."""
if not data:
return None
try:
if hasattr(message_type, 'FromString'):
return message_type.FromString(data)
raise ValueError("Message type does not support deserialization")
except Exception as err:
raise err_unmarshal(err)
class Contract:
"""
Contract defines the smart contract that implements the extended logic of the nested chain.
Matches Go's Contract struct.
"""
def __init__(
self,
config: Optional["Config"] = None,
fsm_config: Optional[PluginFSMConfig] = None,
plugin: Optional["Plugin"] = None,
fsm_id: Optional[int] = None,
):
self.config = configView on GitHub (pinned to ee8197d91d)
Solutions
- Pass the generated message CLASS (FeeParams), not an instance: min_fees = unmarshal(FeeParams, fee_params_bytes).
- Confirm the import points at the generated protobuf module that defines FromString (regenerate code if needed).
- Validate message_type has FromString before the call: if not hasattr(T, 'FromString'): raise TypeError(...).
- Catch the err_unmarshal-wrapped error in check_tx/deliver_tx and return a PluginError response to the FSM.
Example fix
// before min_fees = unmarshal(FeeParams(), fee_params_bytes) # instance, has no FromString // after min_fees = unmarshal(FeeParams, fee_params_bytes) # class
Defensive patterns
Strategy: type-guard
Validate before calling
def is_message_class(t) -> bool:
return isinstance(t, type) and hasattr(t, 'FromString') Type guard
from google.protobuf.message import Message
def is_deserializable(t) -> bool:
return isinstance(t, type) and issubclass(t, Message) Try / catch
try:
min_fees = unmarshal(FeeParams, fee_params_bytes)
except Exception as err:
return PluginCheckResponse(error=err_unmarshal(err)) Prevention
- Pass the message class (FeeParams), never an instance, to unmarshal.
- Verify generated protobuf code is up to date after schema edits.
- Use issubclass(t, Message) assertions in tests for every decoded type.
- Catch wrapped err_unmarshal errors at check_tx/deliver_tx boundaries.
When it happens
Trigger: Calling unmarshal(FeeParams_instance, data) with an instance instead of the class; passing a non-protobuf type (dict, type alias, None class) as message_type; the generated module not imported so a stub is used.
Common situations: Refactoring renamed the generated message class so the old name resolves to something else; passing `FeeParams()` (instance) rather than `FeeParams` (class); forgetting to regenerate protobuf code so FromString is missing on a hand-written stub.
Understand the failure class
Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.
Related errors
- Message does not support serialization
- Could not find types.proto descriptor
- Item too long: {len(item)} bytes (max 255)
- Invalid uint64 value: {value}
- 1
AI-assisted analysis of canopy-network/canopy@ee8197d91d (2026-09-06).
Data as JSON: /api/errors/ee8563eec8efc365.
Report an issue: GitHub.