astral-sh/ruff · error
Expected ScopeKind::Function
Error message
Expected ScopeKind::Function
What it means
Internal panic in Ruff's pep8-naming N804/N805 rule (`invalid_first_argument_name`). The rule is only scheduled for function scopes, so the `let-else` on `ScopeKind::Function` treats any other scope kind as unreachable. Seeing this panic means the visitor was invoked with a non-function scope — a Ruff regression or API misuse, not a problem with the analyzed Python code.
Source
Thrown at crates/ruff_linter/src/rules/pep8_naming/rules/invalid_first_argument_name.rs:213
const fn rule(self) -> Rule {
match self {
Self::Method => Rule::InvalidFirstArgumentNameForMethod,
Self::ClassMethod => Rule::InvalidFirstArgumentNameForClassMethod,
}
}
}
/// N804, N805
pub(crate) fn invalid_first_argument_name(checker: &Checker, scope: &Scope) {
let ScopeKind::Function(ast::StmtFunctionDef {
name,
parameters,
decorator_list,
..
}) = &scope.kind
else {
panic!("Expected ScopeKind::Function")
};
let semantic = checker.semantic();
let Some(parent_scope) = semantic.first_non_type_parent_scope(scope) else {
return;
};
let ScopeKind::Class(parent) = parent_scope.kind else {
return;
};
let function_type = match function_type::classify(
name,
decorator_list,
parent_scope,
semantic,
&checker.settings().pep8_naming.classmethod_decorators,View on GitHub (pinned to 26f38c119c)
Solutions
- Update Ruff to the latest version and retry; search issues for 'Expected ScopeKind::Function' N804/N805 panic and attach your minimized snippet
- Isolate with `ruff check --isolated --select N804,N805 <file>` to confirm, then report upstream if reproducible
- Temporarily disable the rules: `ignore = ["N804", "N805"]` in `[tool.ruff.lint]`
- If calling the rule from Rust, only invoke it for scopes where `matches!(scope.kind, ScopeKind::Function(_))`
Example fix
# before [tool.ruff.lint] select = ["N"] # after (workaround: drop just the crashing rules) [tool.ruff.lint] select = ["N"] ignore = ["N804", "N805"]
Defensive patterns
Strategy: validation
Validate before calling
// Rust caller-side guard
if !matches!(scope.kind, ScopeKind::Function(_)) {
return;
} Type guard
fn is_function_scope(scope: &Scope) -> bool {
matches!(scope.kind, ScopeKind::Function(_))
} Prevention
- Invoke N804/N805 only from the function-scope visit hook
- Keep pep8-naming decorator settings (classmethod/staticmethod decorators) syntactically valid to avoid classifier drift
- Upgrade Ruff promptly; search issues for the exact panic text
- Keep a CI job that runs the linter on a canary corpus to catch version regressions before rollout
When it happens
Trigger: Running `ruff check --select N804,N805` where the rule visitor reaches a module, class, or lambda scope instead of a function scope; or calling `invalid_first_argument_name` directly from the ruff_linter API with a wrong `Scope`. Practically only via a Ruff bug, a fork, or a plugin hooking the wrong traversal point.
Common situations: After upgrading Ruff and linting code with metaclasses/methods (the rules' main domain); patched builds that changed the scope stack; running an old Ruff against newly supported syntax that misclassifies scopes.
Related errors
- Expected Stmt::ImportFrom
- Expected ScopeKind::Function | ScopeKind::Lambda
- Expected Stmt::Import | Stmt::ImportFrom
- Expected CmpOp::Is | CmpOp::IsNot
- extra use-def data should have been retained
AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05).
Data as JSON: /api/errors/cc5e6814fd045a7f.
Report an issue: GitHub.