pydantic/monty · critical
LoadCell: entry is not a Cell
Error message
LoadCell: entry is not a Cell
What it means
`load_cell` reads the heap entry for a local slot's cell to push its value; this panic fires when the entry stored at `cell_id` is not a `Cell`. Cells live at known fixed slots in a frame's locals region, so a mismatch means the heap entry was replaced by another type — an interpreter invariant failure, not a Python-level exception (a genuinely unbound cell raises NameError/UnboundLocalError instead).
Source
Thrown at crates/monty/src/bytecode/vm/mod.rs:2478
if matches!(self.globals[slot as usize], Value::Undefined) {
let name = self.global_name(slot);
return Err(self.name_error(slot, name));
}
let old_value = mem::replace(&mut self.globals[slot as usize], Value::Undefined);
old_value.drop_with(self);
Ok(())
}
/// Loads from a closure cell and pushes onto the stack.
///
/// The cell `HeapId` is read from the frame's local variable slot on the stack
/// (cells are stored as `Value::Ref(cell_id)` at known positions in the locals region).
/// Returns a `NameError` if the cell value is undefined (free variable not bound).
fn load_cell(&mut self, slot: u16) -> RunResult<()> {
let cell_id = self.cell_id_from_local(slot);
let value = match self.heap.get(cell_id) {
HeapData::Cell(c) => c.0.clone_with_heap(self),
_ => panic!("LoadCell: entry is not a Cell"),
};
// An undefined value raises the error CPython picks by cell kind: the
// free-variable NameError only for a cell *captured* from an enclosing
// function; an unbound cell this frame owns (a local captured by
// nested functions) is an ordinary UnboundLocalError, like any local.
if matches!(value, Value::Undefined) {
value.drop_with(self);
let name = self.current_frame.code.local_name(slot);
Err(if self.is_free_var_slot(slot) {
self.free_var_error(name)
} else {
self.unbound_local_error(slot, name)
})
} else {
self.push(value);
Ok(())
}View on GitHub (pinned to adc986b362)
Solutions
- File a bug with the reproducing Python snippet — the cell HeapId points at a non-Cell heap entry
- Audit code paths that write to local slots holding cells (StoreCell, frame setup) for type-tagging mistakes
- Run the monty test suite plus memory-model-checks to find the refcount/drop path corrupting the entry
Example fix
// not applicable — internal interpreter bug, not a caller-fixable condition
Defensive patterns
Strategy: fallback
Try / catch
// Not a catchable library error — treat as a bug report.
match monty.run(closure_code, limits) {
Ok(_) => (),
Err(e) => report_bug_with_repro(closure_code, e),
} Prevention
- Report closure/cell reproducers to maintainers
- Run memory-model-checks after changing cell or frame-layout code
- Avoid hand-editing heap entry tagging
When it happens
Trigger: Executing a `LoadCell` opcode (reading a free variable or a local captured by a nested function) when the HeapId in the local slot no longer points to a `HeapData::Cell`; only via heap corruption, an interpreter bug, or fuzzing.
Common situations: Fuzzing Monty (crates/fuzz string_input_panic target); hacking on closures/cell implementation in the VM; a patch that stores a non-cell Value into a cell slot or mishandles heap reuse.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- StoreCell: entry is not a Cell
- DeleteCell: entry is not a Cell
- list_extend: expected List on heap
- LoadCell/StoreCell: expected cell reference in local slot {s
- StableHeap::get - {id:?} out of bounds
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/e5075b21c2f76a4a.
Report an issue: GitHub.