{"record":{"id":"4164cd81792be54a","repo":"pydantic/monty","slug":"dict-items-view-must-reference-a-dict","errorCode":null,"errorMessage":"dict_items view must reference a dict","messagePattern":"dict_items view must reference a dict","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/monty/src/types/dict_view.rs","lineNumber":440,"sourceCode":"    }\n}\n\nimpl<'h> PyTrait<'h> for HeapObjectRead<'h, DictItemsView> {\n    fn py_is_iterable(&self, _vm: &VM<'h>) -> bool {\n        true\n    }\n\n    /// Membership takes a `(key, value)` probe: look the key up, then compare\n    /// the stored value. A non-pair probe can never be a member.\n    fn py_contains_impl(&self, item: &Value, vm: &mut VM<'h>) -> RunResult<Option<bool>> {\n        let dict_id = self.get(vm.heap).dict_id();\n        let Some((key, value)) = cloned_items_view_candidate(item, vm) else {\n            return Ok(Some(false));\n        };\n        defer_drop!(key, vm);\n        defer_drop!(value, vm);\n        let HeapReadOutput::Dict(dict) = vm.heap.read(dict_id) else {\n            panic!(\"dict_items view must reference a dict\");\n        };\n        match dict.dict_get(key, vm) {\n            Ok(Some(existing_value)) => {\n                // Stored value on the left, as CPython's `dictitems_contains` does.\n                let result = existing_value.py_eq(value, vm);\n                existing_value.drop_with(vm);\n                result.map(Some)\n            }\n            Ok(None) => Ok(Some(false)),\n            Err(e) => Err(e),\n        }\n    }\n\n    fn py_type(&self, _vm: &VM<'h>) -> Type {\n        Type::DictItems\n    }\n\n    fn py_iter(&self, vm: &mut VM<'h>) -> RunResult<Value> {","sourceCodeStart":422,"sourceCodeEnd":458,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty/src/types/dict_view.rs#L422-L458","documentation":"Internal panic in the dict-items view `py_contains_impl` (the `in` operator on `dict.items()`). After extracting a candidate (key, value) pair, the code reads the view's backing dict; if the HeapId does not resolve to a Dict, an invariant is broken. Normal membership tests never trigger it.","triggerScenarios":"Evaluating `pair in dict.items()` (or `set <= dict.items()` style comparisons) when the items view's dict_id resolves to a non-Dict heap entry — reachable only through an interpreter bug or heap corruption.","commonSituations":"Seen by Monty developers working on heap entry reuse, view lifetime, or cycle-collection changes; unreachable from correct sandboxed Python execution.","solutions":["Report the reproducing case to the Monty project as a bug.","Trace how the view's dict_id was produced and whether the referenced entry was freed or replaced.","Audit `py_dec_ref_ids` / drop paths for the view and its backing dict."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let HeapReadOutput::Dict(dict) = vm.heap.read(dict_id) else {\n    return Err(internal_error(\"dict_items view must reference a dict\"));\n};","preventionTips":["Audit py_dec_ref_ids for DictItemsView and its backing dict after any heap change.","Prefer holding an owning Value::Ref over a raw HeapId in view structs.","Report any reproduction to maintainers; do not work around it in Python code."],"tags":["rust","internal-error","panic","dict-view","membership-test"],"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-14T16:17:12.679Z"}