pydantic/monty · error

ClassInstanceBody is decode-only

Error message

ClassInstanceBody is decode-only

What it means

`ClassInstanceBody` is another decode-only hand-written prost `Message` impl in wire.rs: its `encode_raw` panics with `unreachable!("ClassInstanceBody is decode-only")`. The struct exists purely to decode class-instance values from the wire; it is never meant to be serialized. Hitting the panic means an encode path reached a decode-only type.

Source

Thrown at crates/monty-proto/src/wire.rs:1066

            1 => encoding::message::merge(
                wire_type,
                self.class_type.get_or_insert_with(TypeBody::default),
                buf,
                ctx,
            ),
            2 => encoding::message::merge(
                wire_type,
                self.instance_id.get_or_insert_with(pb::Uuid::default),
                buf,
                ctx,
            ),
            3 => 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!("ClassInstanceBody is decode-only")
    }

    fn encoded_len(&self) -> usize {
        unreachable!("ClassInstanceBody is decode-only")
    }

    fn clear(&mut self) {
        self.class_type = None;
        self.instance_id = None;
        self.attrs = None;
    }
}

/// Maps a semantic validation failure onto prost's decode error so it
/// surfaces through the normal frame-decode path.
//
// `DecodeError::new` is deprecated but has no public replacement in prost
// 0.14 (`DecodeErrorKind` is crate-private); the deprecation note itself

View on GitHub (pinned to adc986b362)

Solutions

  1. Encode class-instance values through the designated encode representation, never through `ClassInstanceBody`.
  2. If class instances must be encoded, implement real `encode_raw`/`encoded_len` (fields: class_type, instance_id, attrs PairList) or regenerate a prost message for both directions.
  3. Run `make check-proto` to confirm the wire schema and hand-written impls stayed in sync.
  4. Replace the value with an encodable representation before sending.

Example fix

// before
fn encode_raw(&self, _buf: &mut impl BufMut) { unreachable!("ClassInstanceBody is decode-only") }
// after
fn encode_raw(&self, buf: &mut impl BufMut) {
    if let Some(t) = &self.class_type { encoding::message::encode(...); }
    // ...
}
Defensive patterns

Strategy: validation

Validate before calling

// Rust: ensure class instances are encoded via the supported representation
assert!(encodable(value), "ClassInstanceBody is decode-only; use the encode path for class instances");

Prevention

When it happens

Trigger: Serializing a MontyObject representing a class instance (with `class_type`, `instance_id`, `attrs`) through the hand-written `ClassInstanceBody` Message impl — e.g. a worker trying to send a class-instance value back to the parent via this body type.

Common situations: Extending the wire protocol to round-trip new object kinds and accidentally routing class instances into the decode-only struct on the encode side; refactoring `WireObject` conversions so encode and decode no longer use mirrored types.

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


AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13). Data as JSON: /api/errors/055d1edd43a443d3. Report an issue: GitHub.