astral-sh/ruff · error

Expected ScopeKind::Function | ScopeKind::Lambda

Error message

Expected ScopeKind::Function | ScopeKind::Lambda

What it means

Internal panic in Ruff's flake8-unused-arguments implementation (ARG rules). `unused_arguments` dispatches on `scope.kind` and handles `Function` and `Lambda` scopes, treating any other scope kind as unreachable because the checker only invokes the rule for those two scope types. Hitting it signals a violated internal invariant — a Ruff bug, not a user error.

Source

Thrown at crates/ruff_linter/src/rules/flake8_unused_arguments/rules/unused_arguments.rs:530

                        && !visibility::is_abstract(decorator_list, checker.semantic())
                        && !visibility::is_override(decorator_list, checker.semantic())
                        && !visibility::is_overload(decorator_list, checker.semantic())
                    {
                        // we use `method()` here rather than `function()`, as although `__new__` is
                        // an implicit staticmethod, `__new__` methods must always have at least one parameter
                        method(Argumentable::StaticMethod, parameters, scope, checker);
                    }
                }
            }
        }
        ScopeKind::Lambda(ast::ExprLambda { parameters, .. }) => {
            if let Some(parameters) = parameters {
                if checker.is_rule_enabled(Argumentable::Lambda.rule_code()) {
                    function(Argumentable::Lambda, parameters, scope, checker);
                }
            }
        }
        _ => panic!("Expected ScopeKind::Function | ScopeKind::Lambda"),
    }
}

View on GitHub (pinned to 26f38c119c)

Solutions

  1. Pin or upgrade Ruff to a release where the ARG scope dispatch bug is fixed; search the repo issues for 'Expected ScopeKind::Function | ScopeKind::Lambda'
  2. Reproduce with `ruff check --isolated --select ARG <file>` and minimize the file, then report the snippet upstream
  3. Exclude ARG rules from the run (`ignore = ["ARG"]` in `lint`) until fixed
  4. If you call `unused_arguments` from the ruff_linter API, guard your caller to only pass `ScopeKind::Function` or `ScopeKind::Lambda` scopes

Example fix

# before
ruff check --select ARG001,ARG002,ARG005 .

# after (suppress the crashing rule family until the regression is fixed)
[tool.ruff.lint]
ignore = ["ARG"]
Defensive patterns

Strategy: validation

Validate before calling

// Rust caller-side guard before invoking the rule
if !matches!(scope.kind, ScopeKind::Function(_) | ScopeKind::Lambda(_)) {
    return; // skip instead of reaching the panic arm
}

Type guard

fn is_fn_or_lambda_scope(scope: &Scope) -> bool {
    matches!(scope.kind, ScopeKind::Function(_) | ScopeKind::Lambda(_))
}

Prevention

When it happens

Trigger: Linting code where the unused-arguments check is entered from a scope whose `kind` is neither a function nor a lambda (e.g. module/class scope). Only reachable through a Ruff regression, a custom plugin registering the visitor on the wrong scope, or desynced scope stack after parser/semantic-model changes.

Common situations: Running `ruff check --select ARG` on a codebase after a Ruff upgrade that changed scope construction; forks or API consumers of the linter crates that call `unused_arguments` directly with an incorrect scope; exotic syntax triggering a scope-classification bug.

Related errors


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