pydantic/monty · error
TypeBody is decode-only
Error message
TypeBody is decode-only
What it means
`TypeBody` (the decoded wire form of nested type-annotation objects: name, id, origin, attrs) is decode-only in `monty-proto`; its `encode_raw` traps with `unreachable!("TypeBody is decode-only")`. Type bodies are merged field-by-field during decoding (including `PairList` attrs) and converted into `MontyObject`s, never serialized back out. Firing means a decode-only aggregate was fed into an encoder — an internal `monty-proto` bug.
Source
Thrown at crates/monty-proto/src/wire.rs:964
&mut self,
tag: u32,
wire_type: WireType,
buf: &mut impl Buf,
ctx: DecodeContext,
) -> Result<(), DecodeError> {
// Field numbers from `Type` in monty.proto; unknown → skip.
match tag {
1 => encoding::string::merge(wire_type, &mut self.name, buf, ctx),
2 => encoding::message::merge(wire_type, self.id.get_or_insert_with(pb::Uuid::default), buf, ctx),
3 => encoding::int32::merge(wire_type, &mut self.origin, buf, ctx),
4 => encoding::bool::merge(wire_type, &mut self.is_dataclass, buf, ctx),
5 => encoding::message::merge(wire_type, self.attrs.get_or_insert_with(PairList::default), buf, ctx),
_ => skip_field(wire_type, tag, buf, ctx),
}
}
fn encode_raw(&self, _buf: &mut impl BufMut) {
unreachable!("TypeBody is decode-only")
}
fn encoded_len(&self) -> usize {
unreachable!("TypeBody is decode-only")
}
fn clear(&mut self) {
self.name.clear();
self.id = None;
self.origin = 0;
self.is_dataclass = false;
self.attrs = None;
}
}
/// Decode-only `prost::Message` for `NamedTuple`, materializing the
/// `repeated MontyObject values` field straight into `Vec<MontyObject>` (the
/// [`ObjectList`] trick inlined alongside the other two fields) instead of theView on GitHub (pinned to adc986b362)
Solutions
- Encode type-annotation data from `WireObject`/`MontyObject`, never from the decoded `TypeBody`
- Implement real encoding for `TypeBody` if bidirectional use is required
- Audit message field types so `TypeBody` exists only in decode-side structures
- Run `cargo test -p monty-proto` differential tests and `make check-proto`
Example fix
// before type_body.encode_to_vec() // panics: decode-only // after WireObject::from(&monty_object).encode_to_vec()
Defensive patterns
Strategy: type-guard
Validate before calling
// Convert decoded TypeBody back into MontyObject before any further processing/encoding let obj: MontyObject = type_body.into();
Type guard
fn is_decode_only_aggregate(msg: &dyn std::any::Any) -> bool { msg.is::<TypeBody>() } Try / catch
// Avoid statically; encode only WireObject values, never TypeBody
Prevention
- Consume `TypeBody` immediately during decoding into `MontyObject`s
- Never add `TypeBody` fields to serialized (parent→child) messages
- Document the decode-only contract on the type
- Run `make check-proto` plus differential tests when evolving the schema
When it happens
Trigger: Calling any prost encode routine on a `TypeBody` value, or placing `TypeBody` in a message field that is serialized from parent to child.
Common situations: Encountered while evolving the wire schema (e.g. extending type-annotation representation) or in differential tests that try to re-encode decoded nested structures.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- ObjectList is decode-only
- PairList is decode-only
- NamedTupleBody is decode-only
- varargs/varkwargs own no param slot
- checked above
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/42002377b053ff31.
Report an issue: GitHub.