{"record":{"id":"bf3b37be6cd7fb47","repo":"pydantic/monty","slug":"loadcell-storecell-expected-cell-reference-in-local-slot","errorCode":null,"errorMessage":"LoadCell/StoreCell: expected cell reference in local slot {slot}, found {other:?}","messagePattern":"LoadCell/StoreCell: expected cell reference in local slot (.+?), found (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/monty/src/bytecode/vm/mod.rs","lineNumber":2505,"sourceCode":"            let name = self.current_frame.code.local_name(slot);\n            Err(if self.is_free_var_slot(slot) {\n                self.free_var_error(name)\n            } else {\n                self.unbound_local_error(slot, name)\n            })\n        } else {\n            self.push(value);\n            Ok(())\n        }\n    }\n\n    /// Extracts the cell `HeapId` from a local variable slot on the stack.\n    ///\n    /// Cell variables are stored as `Value::Ref(cell_id)` in the frame's locals region.\n    fn cell_id_from_local(&self, slot: u16) -> HeapId {\n        match &self.stack[self.current_frame.stack_base + slot as usize] {\n            Value::Ref(cell_id) => *cell_id,\n            other => panic!(\"LoadCell/StoreCell: expected cell reference in local slot {slot}, found {other:?}\"),\n        }\n    }\n\n    /// Whether `slot` holds a cell captured from an enclosing function (a\n    /// free variable), as opposed to a cell this frame owns. Module frames\n    /// (`function_id: None`) own all their cells — the only module-level\n    /// cells are inlined-comprehension captures.\n    fn is_free_var_slot(&self, slot: u16) -> bool {\n        self.current_frame().function_id.is_some_and(|id| {\n            self.interns\n                .get_function(id)\n                .free_var_slots\n                .iter()\n                .any(|s| s.as_u16() == slot)\n        })\n    }\n\n    /// Creates a NameError for an unbound free variable.","sourceCodeStart":2487,"sourceCodeEnd":2523,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty/src/bytecode/vm/mod.rs#L2487-L2523","documentation":"`cell_id_from_local` extracts a cell's HeapId from a frame's local slot; this panic fires when the slot holds a non-ref value instead of the expected `Value::Ref(cell_id)`. Because the compiler guarantees cell-holding slots are initialized with cell refs before LoadCell/StoreCell run, seeing another value means frame setup or slot writes broke the invariant — an internal error, not a Python exception.","triggerScenarios":"Executing LoadCell or StoreCell (or DeleteCell, which shares this helper) when the local slot for a cell variable contains a plain value rather than a cell reference; reachable only through a VM/compiler bug or heap corruption.","commonSituations":"Altering bytecode emission for closures in the compiler; changing frame layout (stack_base / locals region) so slots shift; fuzzing deep closure patterns.","solutions":["Report the reproducer to Monty maintainers — a cell slot contains a non-ref value","Check that compiler cell-slot allocation matches the VM's `current_frame.stack_base + slot` indexing after any frame-layout change","Run closure-heavy test cases (`make test-cases`) plus memory-model-checks to isolate the frame-setup bug"],"exampleFix":"// not applicable — internal invariant; the panic message includes the offending value for diagnosis","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Internal panic — no user-side catch; isolate and report.\nmatch monty.run(code, limits) {\n    Ok(res) => res,\n    Err(e) => report_bug(code, e),\n}","preventionTips":["Keep compiler cell-slot allocation and VM slot indexing in sync","Run `make test-cases` on closure tests after frame-layout changes","Include the panic's offending value (`{other:?}`) in bug reports"],"tags":["panic","internal","bytecode","closures"],"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"}