{"record":{"id":"b568b5e8ed667c88","repo":"pydantic/monty","slug":"class-member-member-name-missing-from-class-body-locals","errorCode":null,"errorMessage":"class member '{member_name}' missing from class-body locals","messagePattern":"class member '(.+?)' missing from class-body locals","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/monty/src/prepare.rs","lineNumber":1807,"sourceCode":"        };\n        let FunctionState {\n            locals: inner_locals,\n            free_var_map: inner_free_var_map,\n            cell_var_map: inner_cell_var_map,\n            ..\n        } = *inner_state;\n        let namespace_size = inner_locals.len();\n        drop(inner_prepare);\n\n        // Resolve each member to its class-body-local slot. Every member is\n        // assigned in the class body (a method `def` or a class-var `Assign`),\n        // so it is always present as a plain local.\n        let members = members\n            .into_iter()\n            .map(|member| {\n                let slot = inner_locals.get(member.name_id).unwrap_or_else(|| {\n                    let member_name = self.interner.get_str(member.name_id);\n                    panic!(\"class member '{member_name}' missing from class-body locals\")\n                });\n                Identifier::new_with_scope(member.name_id, member.position, slot, NameScope::Local)\n            })\n            .collect::<Vec<_>>();\n\n        // Same-name collision (a known divergence — see `limitations/classes.md`):\n        // a class-body owned cell means a method captured a class-body local that\n        // ALSO has the same name as a variable in an enclosing scope. CPython keeps\n        // these distinct (class-dict entry vs. closure cell); Monty maps one name\n        // to a single slot, so it cannot represent both. Reject cleanly rather than\n        // miscompile (the alternative is a runtime \"expected cell reference\" crash).\n        if let Some(&name_id) = inner_cell_var_map.keys().next() {\n            let name_str = self.interner.get_str(name_id);\n            return Err(ParseError::not_implemented(\n                format!(\n                    \"class member '{name_str}' that shadows a captured variable of the same name from an enclosing scope\"\n                ),\n                position,","sourceCodeStart":1789,"sourceCodeEnd":1825,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty/src/prepare.rs#L1789-L1825","documentation":"After preparing a class body, every declared class member must exist in the class-body scope's local slot map. If a member's name has no slot, class preparation panics — the members pass and the locals pass disagree about what the class body defines. It is an internal compiler invariant, not a user-facing error.","triggerScenarios":"Compiling a class whose members list (from AST analysis) contains a name the class-body scope never registered as a local — e.g. names introduced by exotic statements inside the class body, or a mismatch introduced by changes to member collection.","commonSituations":"Contributors modifying class-body preparation or member enumeration; Python test code with unusual class bodies (del statements, conditional defs, walrus in class scope).","solutions":["Fix member collection so it only reports names the class-body locals pass registers.","Ensure the class-body scope analysis runs before members are mapped to slots.","Reduce the failing class definition and compare slot registration against member enumeration."],"exampleFix":"// before\nlet slot = inner_locals.get(member.name_id).unwrap_or_else(|| panic!(\"class member missing\"));\n// after\n// ensure member enumeration uses the same pass that fills inner_locals\nlet members = collect_class_members(&body); // shared source of truth\nlet slot = inner_locals.get(member.name_id).unwrap_or_else(|| panic!(\"class member '{member_name}' missing from class-body locals\"));","handlingStrategy":"validation","validationCode":"// derive members and locals from the same AST pass\nlet members = collect_class_members(&body);\nfor m in &members { assert!(inner_locals.contains_key(m.name_id)); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use one shared pass for member enumeration and local registration","Test class bodies with del, conditional defs and walrus expressions","Keep class preparation tests in the consolidated class test files"],"tags":["rust","compiler","classes"],"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-14T16:17:12.679Z"}