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) pushView on GitHub (pinned to adc986b362)
Solutions
- Read the postcard/serde error (unwrap the expect temporarily or use `unwrap_err`) to find which type lacks Serialize.
- Add `#[derive(Serialize, Deserialize)]` or a manual impl for any newly added Heap/HeapData/HeapEntry fields.
- Wrap interior-mutable fields (Cell, UnsafeCell) in serializable newtypes that expose their inner value, mirroring how the existing color Cell is handled.
- 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
- Derive Serialize/Deserialize on every new Heap/HeapData field in the same commit.
- Wrap new Cell/UnsafeCell fields in serializable newtypes immediately.
- Run the heap round-trip test after any change to heap entry storage.
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
- deserialize
- dict view must always reference a dict
- dict_keys view must always reference a dict
- HeapReader::read_ptr - id out of bounds
- HeapPtr::entry: slot has been freed
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/16713e1564413c7c.
Report an issue: GitHub.