{"record":{"id":"98fb1d23e8f0c712","repo":"astral-sh/ruff","slug":"calling-find-name-in-mro-on-unknown-should-retur","errorCode":null,"errorMessage":"Calling `find_name_in_mro` on Unknown should return `Some`","messagePattern":"Calling `find_name_in_mro` on Unknown should return `Some`","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ty_python_semantic/src/types/bound_super.rs","lineNumber":960,"sourceCode":"                .map(|properties| properties.getters_only(db)),\n        ))\n    }\n\n    /// Similar to `Type::find_name_in_mro_with_policy`, but performs lookup starting *after* the\n    /// pivot class in the MRO, based on the `owner` type instead of the `super` type.\n    pub(super) fn find_name_in_mro_after_pivot(\n        self,\n        db: &'db dyn Db,\n        env: &ProgramEnvironment<'db>,\n        name: &str,\n        policy: MemberLookupPolicy,\n    ) -> PlaceAndQualifiers<'db> {\n        let owner = self.owner(db);\n        let class = match &owner {\n            SuperOwnerKind::Dynamic(dynamic) => {\n                return Type::Dynamic(*dynamic)\n                    .find_name_in_mro_with_policy(db, env, name, policy)\n                    .expect(\"Calling `find_name_in_mro` on dynamic type should return `Some`\");\n            }\n            SuperOwnerKind::Divergent(_) => {\n                return Type::unknown()\n                    .find_name_in_mro_with_policy(db, env, name, policy)\n                    .expect(\"Calling `find_name_in_mro` on Unknown should return `Some`\");\n            }\n            SuperOwnerKind::Resolved(resolved_owner) => resolved_owner.lookup_anchor,\n        };\n\n        let mut mro_after_pivot = self.skip_until_after_pivot(db, env, owner.iter_mro(db, env));\n        let class_literal = class.class_literal(db);\n        let result =\n            class_literal.class_member_from_mro(db, env, name, policy, mro_after_pivot.clone());\n\n        // TODO: Here we are hard-coding that __class_getitem__ is the only member defined in\n        // typing._Generic in the typeshed, and we are hard-coding its signature. Ideally we would\n        // look that up from the typeshed class, but that would require threading through the\n        // static class literal through the SpecialForm and KnownInstance types that we create.","sourceCodeStart":942,"sourceCodeEnd":978,"githubUrl":"https://github.com/astral-sh/ruff/blob/15f3fe6b15a5f00172f34b0f542f8ea277f5a586/crates/ty_python_semantic/src/types/bound_super.rs#L942-L978","documentation":"The sibling guard of the dynamic case: when a `super()` owner is Divergent, lookup falls back to Type::unknown(), whose MRO lookup is guaranteed to return Some (Unknown degrades to object-level members). The expect fires if the Unknown-type lookup ever returns None.","triggerScenarios":"`super().attr` where the owner resolved to a divergent type (e.g., after narrowing in possibly-unreachable code) and the Unknown MRO lookup returns None - an invariant break in the base lookup path, not something the Python source controls directly.","commonSituations":"Same class of regression as the dynamic case: member-lookup policy changes or early None returns; typically hit in narrowing-heavy code or via fuzzers.","solutions":["File a ty issue with the snippet (super() under divergent narrowing) and the backtrace","As a contributor: keep the Some(undefined place) contract for Unknown in find_name_in_mro_with_policy; add a divergent-owner super() test","Reproduce under the latest ty build to check whether a recent lookup refactor already fixed it"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| check_file(&db, file)));\nmatch result {\n    Ok(diags) => diags,\n    Err(payload) => { log::warn!(\"ty panicked in super() lookup (divergent owner) on {}: {:?}\", file, payload); vec![] }\n}","preventionTips":["Report the snippet when super() panics under narrowing-heavy or unreachable code","Preserve the Some-return contract for Unknown lookups when refactoring find_name_in_mro_with_policy","Fuzz super() member access alongside narrowing constructs"],"tags":["rust","ty","super","mro","unknown","panic"],"backgroundTag":"mro-lookup-returned-none","analyzedSha":"15f3fe6b15a5f00172f34b0f542f8ea277f5a586","analyzedAt":"2026-08-20T16:33:49.445Z","contentChangedAt":"2026-08-20T16:33:49.445Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}