pydantic/monty · error

serialize

Error message

serialize

What it means

Panic from `postcard::to_allocvec(&heap).expect("serialize")` in a heap round-trip test (crates/monty/src/heap/mod.rs:2539). It means serializing the `Heap` with postcard failed — typically because some heap-contained type does not implement `Serialize`, or the data contains state postcard cannot encode (e.g. UnsafeCell/interior mutability fields like the per-entry color Cell not wrapped in a serializable newtype).

Source

Thrown at crates/monty/src/heap/mod.rs:2539

    }

    #[test]
    fn pending_purple_cycle_round_trips_through_serde() {
        // A snapshot can be taken between any two bytecode instructions, so
        // entries flagged Purple by `dec_ref` but not yet visited by the
        // collector must survive serde round-trips. Otherwise a cycle that
        // becomes garbage just before snapshot would leak permanently after
        // restore (the post-restore VM would never re-touch it).
        let mut heap = Heap::new(16, ResourceTracker::default());
        let id = alloc_self_cycle(&heap);
        // Drop the caller's external ref so the entry is genuinely
        // unreachable except via its self-pointer. dec_ref flags Purple.
        heap.dec_ref(id); // rc 2 → 1
        assert_eq!(heap.purple_count, 1);
        assert_eq!(heap.entries.get(id).color.get(), CcColor::Purple);

        // Round-trip through postcard.
        let bytes = postcard::to_allocvec(&heap).expect("serialize");
        let mut restored: Heap = postcard::from_bytes(&bytes).expect("deserialize");

        // `purple_count` and the per-entry color must round-trip.
        assert_eq!(restored.purple_count, 1);
        assert_eq!(restored.entries.get(id).color.get(), CcColor::Purple);

        // Run the collector on the restored heap; the cycle is unreachable
        // and must be reclaimed.
        restored.collect_cycles();
        assert!(!is_alive(&restored, id));
        assert_eq!(restored.purple_count, 0);
    }

    #[test]
    fn isolated_cycle_with_duplicate_child_refs_is_collected() {
        // Regression: an unreachable cycle where one element references its
        // sibling multiple times within its child list. The mark phase must
        // (a) decrement the sibling's refcount once per edge, and (b) push

View on GitHub (pinned to adc986b362)

Solutions

  1. Read the postcard/serde error (unwrap the expect temporarily or use `unwrap_err`) to find which type lacks Serialize.
  2. Add `#[derive(Serialize, Deserialize)]` or a manual impl for any newly added Heap/HeapData/HeapEntry fields.
  3. Wrap interior-mutable fields (Cell, UnsafeCell) in serializable newtypes that expose their inner value, mirroring how the existing color Cell is handled.
  4. Keep the round-trip test compiling by updating both serialize and deserialize paths together (see also error 183).

Example fix

// before
struct EntryColor(Cell<CcColor>); // no Serialize impl
// after
impl Serialize for EntryColor {
    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        self.0.get().serialize(s)
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// compile-time: ensure all heap types derive Serialize
fn assert_serialize<T: serde::Serialize>() {}
let _ = assert_serialize::<Heap>;

Type guard

fn can_serialize<T: serde::Serialize>(v: &T) -> bool {
    serde::Serialize::serialize(v, serde::__private::ser::Error::custom as fn(_) -> _).is_ok() // prefer postcard::to_allocvec(v).is_ok()
}

Try / catch

match postcard::to_allocvec(&heap) {
    Ok(bytes) => { /* round-trip */ }
    Err(e) => panic!("serialize failed: {e:?}"),
}

Prevention

When it happens

Trigger: Running the snapshot/serialization test after adding a field to `Heap`, `HeapData`, `List`, or `HeapEntry` without deriving/implementing `serde::Serialize`; or serializing a heap whose entries hold non-serializable interior-mutable state (Cell, UnsafeCell, raw pointers).

Common situations: Developers extending `HeapData` variants or heap metadata (colors, purple_count bookkeeping) in crates/monty/src/heap/ and forgetting to update the serde impls; also when a new interior-mutable field (Cell<Color>) is added and the manual Serialize shim is not extended.

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 pydantic/monty@adc986b362 (2026-09-13). Data as JSON: /api/errors/16713e1564413c7c. Report an issue: GitHub.