astral-sh/ruff · error
TypedDictParams should be available for CodeGeneratorKind::T
Error message
TypedDictParams should be available for CodeGeneratorKind::TypedDict
What it means
`own_fields` reads the `total=` default via `typed_dict_params`, which returns Some only when `self.is_typed_dict(db)` holds (a TypedDict detected in the MRO). The expect fires when `own_fields` was called with `field_policy == CodeGeneratorKind::TypedDict` for a class that `is_typed_dict` does not recognize - two classification queries disagreeing about the same class.
Source
Thrown at crates/ty_python_semantic/src/types/class/static_literal.rs:2651
let table = place_table(db, class_body_scope);
let use_def = use_def_map(db, class_body_scope);
// `own_fields(..., NamedTuple)` is called while constructing the class's MRO because the
// field types determine the synthesized tuple base. `typed_dict_params` also queries the
// class's MRO, so only read the `total` default when collecting `TypedDict` fields.
let typed_dict_fields_are_required_by_default =
if field_policy == CodeGeneratorKind::TypedDict {
self.typed_dict_params(db)
.expect("TypedDictParams should be available for CodeGeneratorKind::TypedDict")
.contains(TypedDictParams::TOTAL)
} else {
false
};
let dataclass_kw_only_default = field_policy.is_dataclass_like().then(|| {
let own_field_policy =
CodeGeneratorKind::from_class(db, self.into()).unwrap_or(field_policy);
self.has_dataclass_param(db, own_field_policy, DataclassFlags::KW_ONLY)
});
let mut kw_only_sentinel_field_seen = false;
let mut field_declarations = Vec::new();
for (symbol_id, declarations) in use_def.all_end_of_scope_symbol_declarations() {
// Here, we exclude all declarations that are not annotated assignments. We need this because
// things like function definitions and nested classes would otherwise be considered dataclass
// fields. The check is too broad in the sense that it also excludes (weird) constructs where
// a symbol would have multiple declarations, one of which is an annotated assignment. If we
// want to improve this, we could instead pass a definition-kind filter to the use-def map
// query, or to the `symbol_from_declarations` call below. Doing so would potentially require
// us to generate a union of `__init__` methods.
if declarations.clone().any_reachable(db, |declaration| {
declaration.is_defined_and(|declaration| {
!matches!(
declaration.kind(db),
DefinitionKind::AnnotatedAssignment(..)
)View on GitHub (pinned to 15f3fe6b15)
Solutions
- Derive both `CodeGeneratorKind::from_class` and `is_typed_dict`/`typed_dict_params` from a single classification query so they cannot disagree.
- Replace the expect with a let-else treating a missing params as non-total, and assert the classification invariant in a debug build.
- Add an mdtest reproducing the class shape (e.g. indirect TypedDict inheritance) and run the ty_python_semantic mdtests.
- Report upstream with the reproducer if stock ty is affected.
Example fix
// before
self.typed_dict_params(db).expect("TypedDictParams should be available for CodeGeneratorKind::TypedDict")
// after
let Some(params) = self.typed_dict_params(db) else {
debug_assert!(false, "TypedDict classification mismatch");
return Box::default();
}; Defensive patterns
Strategy: try-catch
Try / catch
let fields = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
class.fields(db, specialization, field_policy)
}))
.unwrap_or_else(|_| Box::default()); Prevention
- Report the exact class statement and its bases; both classification queries must be shown the same code.
- Simplify subclass chains through typing/typing_extensions TypedDict mixes when narrowing a repro.
- Contributors: run the TypedDict mdtests after any change to classification queries.
When it happens
Trigger: Computing fields for a class whose code generator kind is TypedDict while `typed_dict_params` returns None because `is_typed_dict(db)` is false - e.g. TypedDict subclass chains, typing/typing_extensions mixes, or a classification refactor that updated one query but not the other.
Common situations: Modifying TypedDict detection in ty (adding decorator-based or dynamic TypedDicts); usually triggered by mdtests exercising exotic class statements shortly after such a change.
Related errors
- TypedDict code generation should use a TypedDict instance
- Will return Some() when called on class literal
- Expected `NamedTuple` definition to be an assignment
- Expected `NamedTuple` definition r.h.s. to be a call express
- typevar should be interned before ordering
AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-08-20).
Data as JSON: /api/errors/b4efd34a45669c6e.
Report an issue: GitHub.