{"record":{"id":"94381166e334ff9e","repo":"pydantic/monty","slug":"entry-just-allocated","errorCode":null,"errorMessage":"entry just allocated","messagePattern":"entry just allocated","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/monty/src/heap/mod.rs","lineNumber":2326,"sourceCode":"    };\n\n    /// Returns whether a heap entry is still allocated at `id`.\n    fn is_alive(heap: &Heap, id: HeapId) -> bool {\n        heap.entries.iter().any(|(other, _)| other == id)\n    }\n\n    /// Allocates a self-referencing one-element list and returns its id.\n    ///\n    /// The list's items become `[Value::Ref(id)]` and its refcount is bumped\n    /// to 2 to reflect both the caller's ref and the new self-reference.\n    fn alloc_self_cycle(heap: &Heap) -> HeapId {\n        let id = heap.allocate(HeapData::List(List::new(vec![])));\n        let entry = heap\n            .entries\n            .iter()\n            .find(|(other, _)| *other == id)\n            .map(|(_, e)| e)\n            .expect(\"entry just allocated\");\n        // SAFETY: no other borrow into this entry's data exists during the test.\n        let data = unsafe { &mut *entry.data.0.get() };\n        match data {\n            HeapData::List(list) => {\n                list.set_contains_refs();\n                list.as_vec_mut().push(Value::Ref(id));\n            }\n            _ => unreachable!(),\n        }\n        // The new self-pointer counts as one more reference into the entry.\n        heap.inc_ref(id);\n        id\n    }\n\n    /// Allocates a two-element cycle where one direction has multiplicity 3:\n    /// `P → [A, A, A]` and `A → [P]`. Returns `(p_id, a_id)`.\n    ///\n    /// Final refcounts: `P.rc = 2` (alloc + one edge from A), `A.rc = 4`","sourceCodeStart":2308,"sourceCodeEnd":2344,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty/src/heap/mod.rs#L2308-L2344","documentation":"This is a test-only panic from `expect(\"entry just allocated\")` in the cycle-collection unit-test helper `alloc_self_cycle` (crates/monty/src/heap/mod.rs:2326). After `heap.allocate(...)` returns an id, the helper scans `heap.entries` for the matching entry; the expect fires only if that freshly allocated id is not found. It is an internal invariant assertion, not a runtime error surfaced to library users.","triggerScenarios":"Running the heap unit tests where `alloc_self_cycle` iterates `heap.entries.iter().find(|(other, _)| *other == id)` and the id returned by `Heap::allocate` is not present among the iterated entries — e.g. if `HeapEntriesIter` skips live slots, if allocate returned a freed/reused id, or if entries storage was mutated between allocate and the find.","commonSituations":"Developers modifying `StableHeap` iteration (`HeapEntriesIter::new`) or `Heap::allocate`/free-list reuse in crates/monty/src/heap/, breaking the guarantee that a just-allocated id is immediately visible to iteration; also seen when a test allocator change (ResourceTracker limits, page allocation) silently fails to insert the entry.","solutions":["Verify `Heap::allocate` returned a real id and the tracker did not reject/abort the allocation; print `id` before the find.","Check that the `HeapEntriesIter` used by `heap.entries.iter()` yields initialized, live slots (compare with `StableHeap::len`).","Ensure no `dec_ref`/free of the entry happened between `allocate` and the lookup in the test helper.","If the panic appears after refactoring heap internals, restore the invariant that allocate appends/reuses a slot before returning, or use `heap.entries.get(id)`/`entry(id)` instead of a linear find."],"exampleFix":"// before\nlet entry = heap.entries.iter().find(|(other, _)| *other == id)\n    .map(|(_, e)| e).expect(\"entry just allocated\");\n// after\nlet entry = heap.entries.entry(id).expect(\"entry just allocated\").into_inner();","handlingStrategy":"validation","validationCode":"assert!(heap.entries.iter().any(|(other, _)| other == id), \"id {id:?} not live before mutation\");","typeGuard":"fn is_alive(heap: &Heap, id: HeapId) -> bool {\n    heap.entries.iter().any(|(other, _)| other == id)\n}","tryCatchPattern":null,"preventionTips":["Use `heap.entries.entry(id)` (Option-returning) instead of a linear find + expect in test helpers.","Keep allocation and mutation of a heap entry in one tightly scoped block with no dec_ref/free between.","After changing StableHeap internals, run the heap unit tests (`cargo test -p monty --lib heap`) before the full suite."],"tags":["rust","panic","unit-test","heap","internal-invariant"],"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"}