{"record":{"id":"70f21f73442c4dc1","repo":"pydantic/monty","slug":"deletecell-entry-is-not-a-cell","errorCode":null,"errorMessage":"DeleteCell: entry is not a Cell","messagePattern":"DeleteCell: entry is not a Cell","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/monty/src/bytecode/vm/mod.rs","lineNumber":2561,"sourceCode":"            panic!(\"StoreCell: entry is not a Cell\")\n        };\n        mem::swap(&mut cell.get_mut(this.heap).0, value);\n    }\n\n    /// Unbinds a closure cell: replaces its contents with `Undefined`, so a\n    /// later [`Self::load_cell`] raises the free-variable `NameError` —\n    /// CPython's `DELETE_DEREF` cleanup of a captured `except ... as` target.\n    /// The only emitter stores `None` first, so the cell is never already\n    /// unbound here (no error path, unlike [`Self::delete_global`]).\n    fn delete_cell(&mut self, slot: u16) {\n        let value = Value::Undefined;\n        // the guard drops the cell's previous contents after the swap\n        let this = self;\n        defer_drop_mut!(value, this);\n\n        let cell_id = this.cell_id_from_local(slot);\n        let HeapReadOutput::Cell(mut cell) = this.heap.read(cell_id) else {\n            panic!(\"DeleteCell: entry is not a Cell\")\n        };\n        mem::swap(&mut cell.get_mut(this.heap).0, value);\n    }\n}\n\n// `heap` is not a public field on VM, so this implementation needs to go here rather than in `heap.rs`\nimpl ContainsHeap for VM<'_> {\n    fn heap(&self) -> &Heap {\n        self.heap\n    }\n    fn heap_mut(&mut self) -> &mut Heap {\n        self.heap\n    }\n}\n\n/// Ensures proper reference-counting cleanup when the VM goes out of scope.\n///\n/// Drains exception stack, operand stack, globals, scheduler state, and JSON","sourceCodeStart":2543,"sourceCodeEnd":2579,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty/src/bytecode/vm/mod.rs#L2543-L2579","documentation":"`delete_cell` (executed by the DeleteCell opcode, e.g. `del x` on a closed-over variable) swaps `Undefined` into the heap Cell behind a local slot; this panic fires when the entry at `cell_id` is not a `Cell`. It signals heap type-tag corruption or an interpreter bug, not a user-facing error — deleting an unbound cell would raise Python-level NameError instead.","triggerScenarios":"Executing `del <cellvar>` when the cell HeapId in the local slot resolves to a non-Cell heap entry; reachable only through heap corruption or an interpreter defect.","commonSituations":"Fuzzing; changing cell lifecycle code (creation, drop, cycle collection); a patch reusing HeapIds across heap types.","solutions":["Report the reproducer to Monty maintainers","Audit cell drop/dec_ref paths for frees that leave a stale HeapId in the local slot","Run the memory-model-checks test binary over cell/closure tests"],"exampleFix":"// not applicable — internal invariant violation","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":["Run cell/closure tests under memory-model-checks after del/cell edits","Never reuse HeapIds across heap types","Report reproducers with the exact `del` statement"],"tags":["panic","internal","heap","closures","del"],"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"}