{"record":{"id":"16713e1564413c7c","repo":"pydantic/monty","slug":"serialize","errorCode":null,"errorMessage":"serialize","messagePattern":"serialize","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/monty/src/heap/mod.rs","lineNumber":2539,"sourceCode":"    }\n\n    #[test]\n    fn pending_purple_cycle_round_trips_through_serde() {\n        // A snapshot can be taken between any two bytecode instructions, so\n        // entries flagged Purple by `dec_ref` but not yet visited by the\n        // collector must survive serde round-trips. Otherwise a cycle that\n        // becomes garbage just before snapshot would leak permanently after\n        // restore (the post-restore VM would never re-touch it).\n        let mut heap = Heap::new(16, ResourceTracker::default());\n        let id = alloc_self_cycle(&heap);\n        // Drop the caller's external ref so the entry is genuinely\n        // unreachable except via its self-pointer. dec_ref flags Purple.\n        heap.dec_ref(id); // rc 2 → 1\n        assert_eq!(heap.purple_count, 1);\n        assert_eq!(heap.entries.get(id).color.get(), CcColor::Purple);\n\n        // Round-trip through postcard.\n        let bytes = postcard::to_allocvec(&heap).expect(\"serialize\");\n        let mut restored: Heap = postcard::from_bytes(&bytes).expect(\"deserialize\");\n\n        // `purple_count` and the per-entry color must round-trip.\n        assert_eq!(restored.purple_count, 1);\n        assert_eq!(restored.entries.get(id).color.get(), CcColor::Purple);\n\n        // Run the collector on the restored heap; the cycle is unreachable\n        // and must be reclaimed.\n        restored.collect_cycles();\n        assert!(!is_alive(&restored, id));\n        assert_eq!(restored.purple_count, 0);\n    }\n\n    #[test]\n    fn isolated_cycle_with_duplicate_child_refs_is_collected() {\n        // Regression: an unreachable cycle where one element references its\n        // sibling multiple times within its child list. The mark phase must\n        // (a) decrement the sibling's refcount once per edge, and (b) push","sourceCodeStart":2521,"sourceCodeEnd":2557,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty/src/heap/mod.rs#L2521-L2557","documentation":"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).","triggerScenarios":"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).","commonSituations":"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.","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)."],"exampleFix":"// before\nstruct EntryColor(Cell<CcColor>); // no Serialize impl\n// after\nimpl Serialize for EntryColor {\n    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {\n        self.0.get().serialize(s)\n    }\n}","handlingStrategy":"try-catch","validationCode":"// compile-time: ensure all heap types derive Serialize\nfn assert_serialize<T: serde::Serialize>() {}\nlet _ = assert_serialize::<Heap>;","typeGuard":"fn can_serialize<T: serde::Serialize>(v: &T) -> bool {\n    serde::Serialize::serialize(v, serde::__private::ser::Error::custom as fn(_) -> _).is_ok() // prefer postcard::to_allocvec(v).is_ok()\n}","tryCatchPattern":"match postcard::to_allocvec(&heap) {\n    Ok(bytes) => { /* round-trip */ }\n    Err(e) => panic!(\"serialize failed: {e:?}\"),\n}","preventionTips":["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."],"tags":["rust","serde","postcard","serialization","heap"],"backgroundTag":"json-marshal-failed","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"}