{"record":{"id":"af1938eba7e93daa","repo":"astral-sh/ruff","slug":"expected-namedtuple-definition-r-h-s-to-be-a-ca","errorCode":null,"errorMessage":"Expected `NamedTuple` definition r.h.s. to be a call expression","messagePattern":"Expected `NamedTuple` definition r\\.h\\.s\\. to be a call expression","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ty_python_semantic/src/types/class/named_tuple.rs","lineNumber":455,"sourceCode":"            })\n        }\n    }\n\n    fn spec(self, db: &'db dyn Db) -> NamedTupleSpec<'db> {\n        #[salsa::tracked(\n            returns(copy),\n            cycle_initial=|db, _, _| NamedTupleSpec::unknown(db),\n            heap_size=ruff_memory_usage::heap_size\n        )]\n        fn deferred_spec<'db>(db: &'db dyn Db, definition: Definition<'db>) -> NamedTupleSpec<'db> {\n            let python_file = definition.python_file(db);\n            let module = parsed_module(db, python_file).load(db);\n            let node = definition\n                .kind(db)\n                .value(&module)\n                .expect(\"Expected `NamedTuple` definition to be an assignment\")\n                .as_call_expr()\n                .expect(\"Expected `NamedTuple` definition r.h.s. to be a call expression\");\n            match definition_expression_type(db, definition, &node.arguments.args[1]) {\n                Type::KnownInstance(KnownInstanceType::NamedTupleSpec(spec)) => spec,\n                _ => NamedTupleSpec::unknown(db),\n            }\n        }\n\n        match self.anchor(db) {\n            DynamicNamedTupleAnchor::CollectionsDefinition { spec, .. }\n            | DynamicNamedTupleAnchor::ScopeOffset { spec, .. } => *spec,\n            DynamicNamedTupleAnchor::TypingDefinition(definition) => deferred_spec(db, *definition),\n        }\n    }\n\n    fn fields(self, db: &'db dyn Db) -> &'db [NamedTupleField<'db>] {\n        self.spec(db).fields(db)\n    }\n\n    /// Returns the field declared directly on this dynamic named tuple, if any.","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/astral-sh/ruff/blob/d1087a4b9e03d253a88703f34e0869ee4b805456/crates/ty_python_semantic/src/types/class/named_tuple.rs#L437-L473","documentation":"The second assertion in `deferred_spec`: after confirming the definition is an assignment, the value must be the `NamedTuple(...)` call expression, because the code then reads `node.arguments.args[1]` (the fields list). The `as_call_expr().expect(...)` fires when the RHS is not a call.","triggerScenarios":"Resolving a typing-module NamedTuple spec where the anchored definition's value is not an `ast::ExprCall` - e.g. `P = NamedTuple` (bare alias) or a rebinding got anchored by mistake. Note the same code also indexes `args[1]`, so zero/one-argument calls are a neighboring crash risk.","commonSituations":"Broadening NamedTuple detection to bare aliases or star-call forms; refactors that anchor definitions before validating the call shape; stale anchors after edits.","solutions":["Anchor only after the RHS matches a `NamedTuple`/`collections.namedtuple` call with the expected arity.","Use `as_call_expr()` with a let-else returning `NamedTupleSpec::unknown(db)` so malformed anchors degrade instead of panicking.","Add mdtests covering `P = NamedTuple`, calls missing the fields argument, and keyword forms.","Report upstream if reachable without source changes."],"exampleFix":"// before\n.as_call_expr()\n.expect(\"Expected `NamedTuple` definition r.h.s. to be a call expression\");\n\n// after\nlet Some(call) = value.as_call_expr() else {\n    return NamedTupleSpec::unknown(db);\n};","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let spec = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    named_tuple.spec(db)\n}))\n.unwrap_or_else(|_| NamedTupleSpec::unknown(db));","preventionTips":["Prefer the two-argument functional form `P = NamedTuple('P', [...])` in reproducers; degenerate forms stress adjacent panics (args[1] indexing).","Report bare-alias (`P = NamedTuple`) or rebound cases with a minimal file.","Run the NamedTuple mdtests after touching detection code."],"tags":["rust","panic","expect","ty","namedtuple","call-expression","invariant"],"backgroundTag":"rust-expect-panic","analyzedSha":"d1087a4b9e03d253a88703f34e0869ee4b805456","analyzedAt":"2026-08-20T16:33:49.445Z","contentChangedAt":"2026-08-20T16:33:49.445Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}