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

  1. Update Ruff to the latest version and retry; search issues for 'Expected ScopeKind::Function' N804/N805 panic and attach your minimized snippet
  2. Isolate with `ruff check --isolated --select N804,N805 <file>` to confirm, then report upstream if reproducible
  3. Temporarily disable the rules: `ignore = ["N804", "N805"]` in `[tool.ruff.lint]`
  4. 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

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


AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05). Data as JSON: /api/errors/cc5e6814fd045a7f. Report an issue: GitHub.