astral-sh/ruff · error
Calling `find_name_in_mro` on dynamic type should return `So
Error message
Calling `find_name_in_mro` on dynamic type should return `Some`
What it means
In `super()` member lookup (find_name_in_mro_after_pivot), when the super owner is dynamic (Any/Unknown), lookup delegates to Type::Dynamic::find_name_in_mro_with_policy, which is guaranteed to return Some because dynamic types fall back to object-level members with an undefined place. The expect enforces that guarantee.
Source
Thrown at crates/ty_python_semantic/src/types/bound_super.rs:955
descriptor_error.map(MemberLookupErrorKind::DescriptorGet),
instance
.and_then(|_| attribute.place.ignore_possibly_undefined())
.and_then(|ty| ty.property_deprecations(db))
// `super` delegates reads to the owner's descriptors, but not writes or deletions.
.map(|properties| properties.getters_only(db)),
))
}
/// Similar to `Type::find_name_in_mro_with_policy`, but performs lookup starting *after* the
/// pivot class in the MRO, based on the `owner` type instead of the `super` type.
pub(super) fn find_name_in_mro_after_pivot(
self,
db: &'db dyn Db,
env: &ProgramEnvironment<'db>,
name: &str,
policy: MemberLookupPolicy,
) -> PlaceAndQualifiers<'db> {
let owner = self.owner(db);
let class = match &owner {
SuperOwnerKind::Dynamic(dynamic) => {
return Type::Dynamic(*dynamic)
.find_name_in_mro_with_policy(db, env, name, policy)
.expect("Calling `find_name_in_mro` on dynamic type should return `Some`");
}
SuperOwnerKind::Divergent(_) => {
return Type::unknown()
.find_name_in_mro_with_policy(db, env, name, policy)
.expect("Calling `find_name_in_mro` on Unknown should return `Some`");
}
SuperOwnerKind::Resolved(resolved_owner) => resolved_owner.lookup_anchor,
};
let mut mro_after_pivot = self.skip_until_after_pivot(db, env, owner.iter_mro(db, env));
let class_literal = class.class_literal(db);
let result =
class_literal.class_member_from_mro(db, env, name, policy, mro_after_pivot.clone());View on GitHub (pinned to 15f3fe6b15)
Solutions
- File a ty issue with the `super()` expression, the member name, and the backtrace
- As a contributor: audit find_name_in_mro_with_policy early-return paths; they must still yield Some with an undefined place for dynamic types
- Add a regression test covering `super().<member>` in a class with an untyped/dynamic base
Defensive patterns
Strategy: fallback
Try / catch
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| check_file(&db, file)));
match result {
Ok(diags) => diags,
Err(payload) => { log::warn!("ty panicked in super() lookup on {}: {:?}", file, payload); vec![] }
} Prevention
- Report `super().<member>` panics with the exact member name - it identifies the filtered-lookup path
- When changing MemberLookupPolicy or find_name_in_mro early returns, preserve the Some(undefined-place) contract for dynamic types
- Keep a regression test for super() in untyped classes
When it happens
Trigger: `super().attr` where the enclosing class resolves to a dynamic type, and the dynamic MRO lookup returns None - an internal regression in the dynamic lookup path (early returns or name filtering) rather than a property of the user's Python input.
Common situations: Refactors of find_name_in_mro or MemberLookupPolicy that introduce early None returns (e.g., filtered member names) without preserving the dynamic fallback; usually surfaced by fuzzing or large codebases with untyped classes.
Related errors
- The meta-type of an instance-like type should always have an
- `find_name_in_mro` should return `Some` for a class literal
- Calling `find_name_in_mro` on Unknown should return `Some`
- Will return Some() when called on class literal
- extra use-def data should have been retained
AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-08-20).
Data as JSON: /api/errors/0120627f34eb8b63.
Report an issue: GitHub.