pydantic/monty · critical
StoreCell: entry is not a Cell
Error message
StoreCell: entry is not a Cell
What it means
`store_cell` swaps a new value into the heap Cell behind a local slot; this panic fires if the heap entry at `cell_id` is not a `Cell`. Cell entries are allocated once per closed-over variable, so a type mismatch means heap corruption or an interpreter bug, not a Python-level failure.
Source
Thrown at crates/monty/src/bytecode/vm/mod.rs:2543
let name_str = match name {
Some(id) => self.interns.get_str(id).to_string(),
None => "<free var>".to_string(),
};
ExcType::name_error_free_variable(&name_str).into()
}
/// Pops the top of stack and stores it in a closure cell.
///
/// The cell `HeapId` is read from the frame's local variable slot on the stack.
fn store_cell(&mut self, slot: u16) {
let value = self.pop();
// The guard will clean up the new value if we panic, or the old value if we swap
let this = self;
defer_drop_mut!(value, this);
let cell_id = this.cell_id_from_local(slot);
let HeapReadOutput::Cell(mut cell) = this.heap.read(cell_id) else {
panic!("StoreCell: entry is not a Cell")
};
mem::swap(&mut cell.get_mut(this.heap).0, value);
}
/// Unbinds a closure cell: replaces its contents with `Undefined`, so a
/// later [`Self::load_cell`] raises the free-variable `NameError` —
/// CPython's `DELETE_DEREF` cleanup of a captured `except ... as` target.
/// The only emitter stores `None` first, so the cell is never already
/// unbound here (no error path, unlike [`Self::delete_global`]).
fn delete_cell(&mut self, slot: u16) {
let value = Value::Undefined;
// the guard drops the cell's previous contents after the swap
let this = self;
defer_drop_mut!(value, this);
let cell_id = this.cell_id_from_local(slot);
let HeapReadOutput::Cell(mut cell) = this.heap.read(cell_id) else {
panic!("DeleteCell: entry is not a Cell")View on GitHub (pinned to adc986b362)
Solutions
- File a bug with the smallest Python snippet that triggers it
- Audit cell creation and `py_dec_ref_ids`/drop paths for premature frees of cell entries
- Run `cargo test -p monty --features memory-model-checks` on the relevant test binary to catch the refcount bug
Example fix
// not applicable — internal interpreter bug
Defensive patterns
Strategy: fallback
Try / catch
// Internal panic — no user-side catch; isolate and report.
match monty.run(code, limits) {
Ok(res) => res,
Err(e) => report_bug(code, e),
} Prevention
- Audit cell creation/drop paths for premature frees
- Run memory-model-checks on cell tests after lifecycle edits
- Report minimal reproducers
When it happens
Trigger: Executing StoreCell (assigning to a free variable or a local captured by a nested function) when the cell HeapId resolves to a non-Cell heap entry; only via an interpreter bug or heap corruption.
Common situations: Fuzzing Monty; modifying cell allocation/freevariables handling; patches that free a cell and let the HeapId be reallocated as another type.
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
- LoadCell: 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/db66d72f38ba7557.
Report an issue: GitHub.