{"record":{"id":"7a9daa9322290c1e","repo":"pydantic/monty","slug":"list-extend-expected-list-on-heap","errorCode":null,"errorMessage":"list_extend: expected List on heap","messagePattern":"list_extend: expected List on heap","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/monty/src/bytecode/vm/collections.rs","lineNumber":127,"sourceCode":"            let type_ = iterable.py_type_name(this);\n            return Err(if opts_out_of_iter(iterable, this) {\n                ExcType::type_error_not_iterable(&type_)\n            } else {\n                ExcType::type_error_value_after_star(&type_)\n            });\n        }\n\n        {\n            let copied_items: Vec<Value> = collect_iterable(iterable, this)?;\n            defer_drop_mut!(copied_items, this);\n\n            // Check if any copied items are refs (for updating contains_refs)\n            let has_refs = copied_items.iter().any(|v| matches!(v, Value::Ref(_)));\n\n            // Extend the list\n            if let Value::Ref(id) = list_ref {\n                let HeapReadOutput::List(mut list) = this.heap.read(*id) else {\n                    panic!(\"list_extend: expected List on heap\");\n                };\n                let list = list.get_mut(this.heap);\n                // Update contains_refs before extending\n                if has_refs {\n                    list.set_contains_refs();\n                }\n                list.as_vec_mut().append(copied_items);\n            }\n        }\n\n        // Push list_ref back on the stack (don't drop it)\n        let (list_ref, this) = list_ref_guard.into_parts();\n        this.push(list_ref);\n        Ok(())\n    }\n\n    /// Converts a list to a tuple.\n    ///","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty/src/bytecode/vm/collections.rs#L109-L145","documentation":"This is an internal panic in Monty's list extension path: `list_extend` looked up the target list's HeapId in the heap and found an entry that is not a `List`. The VM tracks lists as `Value::Ref(id)` with the heap entry type fixed at allocation time, so this can only happen if the heap entry type and the stack value disagree — an internal invariant violation, not a user-facing Python error.","triggerScenarios":"Calling Python code that extends a list (e.g. `list.extend`, `+=` on a list, or the ListExtend opcode) when the heap entry behind the list's HeapId has been corrupted, freed and reallocated as another type, or when a bug mis-tags a heap entry; effectively only reachable via a monty interpreter bug or fuzzing, not via ordinary API use.","commonSituations":"Running fuzz targets (crates/fuzz) over Monty; developing a new opcode or heap type in monty that allocates or re-tags heap entries; misuse of low-level Heap APIs in a patch that lets a HeapId be reused for a different HeapData variant.","solutions":["Report the input/program to the Monty maintainers with a minimal reproducer — this indicates a heap type-tag invariant bug","Check recent changes to heap allocation or list opcodes for places where a HeapId could be freed and reallocated as a non-List entry","Run `make test-memory-model-checks` (or the relevant test binary with `--features memory-model-checks`) to surface the refcount/drop bug causing the mismatch","As a workaround, reduce the Python program to the smallest snippet that triggers it and avoid that construct until fixed"],"exampleFix":"// not applicable — bug is inside crates/monty/src/bytecode/vm/collections.rs;\n// the panic already documents the violated assumption","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Panics are not catchable via RunResult; treat any panic as a monty bug.\n// Isolate executions so a panic cannot take down the host (e.g. run in a\n// worker subprocess, as monty-pool/monty subprocess already do).\nmatch monty.run(code, limits) {\n    Ok(res) => res,\n    Err(e) => report_bug(e),\n}","preventionTips":["Keep monty updated; these panics are bugs to report, not user errors","Attach the minimal Python snippet when filing the issue","Run fuzz targets after touching heap or opcode code"],"tags":["panic","internal","heap","list"],"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"}