{"record":{"id":"42002377b053ff31","repo":"pydantic/monty","slug":"typebody-is-decode-only","errorCode":null,"errorMessage":"TypeBody is decode-only","messagePattern":"TypeBody is decode-only","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/monty-proto/src/wire.rs","lineNumber":964,"sourceCode":"        &mut self,\n        tag: u32,\n        wire_type: WireType,\n        buf: &mut impl Buf,\n        ctx: DecodeContext,\n    ) -> Result<(), DecodeError> {\n        // Field numbers from `Type` in monty.proto; unknown → skip.\n        match tag {\n            1 => encoding::string::merge(wire_type, &mut self.name, buf, ctx),\n            2 => encoding::message::merge(wire_type, self.id.get_or_insert_with(pb::Uuid::default), buf, ctx),\n            3 => encoding::int32::merge(wire_type, &mut self.origin, buf, ctx),\n            4 => encoding::bool::merge(wire_type, &mut self.is_dataclass, buf, ctx),\n            5 => encoding::message::merge(wire_type, self.attrs.get_or_insert_with(PairList::default), buf, ctx),\n            _ => skip_field(wire_type, tag, buf, ctx),\n        }\n    }\n\n    fn encode_raw(&self, _buf: &mut impl BufMut) {\n        unreachable!(\"TypeBody is decode-only\")\n    }\n\n    fn encoded_len(&self) -> usize {\n        unreachable!(\"TypeBody is decode-only\")\n    }\n\n    fn clear(&mut self) {\n        self.name.clear();\n        self.id = None;\n        self.origin = 0;\n        self.is_dataclass = false;\n        self.attrs = None;\n    }\n}\n\n/// Decode-only `prost::Message` for `NamedTuple`, materializing the\n/// `repeated MontyObject values` field straight into `Vec<MontyObject>` (the\n/// [`ObjectList`] trick inlined alongside the other two fields) instead of the","sourceCodeStart":946,"sourceCodeEnd":982,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty-proto/src/wire.rs#L946-L982","documentation":"`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.","triggerScenarios":"Calling any prost encode routine on a `TypeBody` value, or placing `TypeBody` in a message field that is serialized from parent to child.","commonSituations":"Encountered while evolving the wire schema (e.g. extending type-annotation representation) or in differential tests that try to re-encode decoded nested structures.","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`"],"exampleFix":"// before\ntype_body.encode_to_vec() // panics: decode-only\n// after\nWireObject::from(&monty_object).encode_to_vec()","handlingStrategy":"type-guard","validationCode":"// Convert decoded TypeBody back into MontyObject before any further processing/encoding\nlet obj: MontyObject = type_body.into();","typeGuard":"fn is_decode_only_aggregate(msg: &dyn std::any::Any) -> bool { msg.is::<TypeBody>() }","tryCatchPattern":"// Avoid statically; encode only WireObject values, never TypeBody","preventionTips":["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"],"tags":["rust","protobuf","wire-protocol","internal-assert"],"backgroundTag":"internal-invariant-violation","analyzedSha":"adc986b362e3961f407868cb118a99fe831b9e61","analyzedAt":"2026-09-13T19:19:18.698Z","contentChangedAt":"2026-09-13T19:19:18.698Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}