{"record":{"id":"6ebba676794eafd9","repo":"astral-sh/ruff","slug":"stack-to-never-be-empty","errorCode":null,"errorMessage":"Stack to never be empty","messagePattern":"Stack to never be empty","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/ruff_linter/src/rules/flake8_commas/rules/trailing_commas.rs","lineNumber":445,"sourceCode":"            (TokenType::Named, TokenType::Def) => Context::new(ContextType::FunctionParameters),\n            (TokenType::Named | TokenType::ClosingBracket, _) => {\n                Context::new(ContextType::CallArguments)\n            }\n            _ => Context::new(ContextType::Tuple),\n        },\n        TokenType::OpeningSquareBracket => match (prev.ty, prev_prev.ty) {\n            (TokenType::Named, TokenType::Def | TokenType::Class | TokenType::Type) => {\n                Context::new(ContextType::TypeParameters)\n            }\n            (TokenType::ClosingBracket | TokenType::Named | TokenType::String, _) => {\n                Context::new(ContextType::Subscript)\n            }\n            _ => Context::new(ContextType::List),\n        },\n        TokenType::OpeningCurlyBracket => Context::new(ContextType::Dict),\n        TokenType::Lambda => Context::new(ContextType::LambdaParameters),\n        TokenType::For => {\n            let last = stack.last_mut().expect(\"Stack to never be empty\");\n            *last = Context::new(ContextType::No);\n            return *last;\n        }\n        TokenType::Comma => {\n            let last = stack.last_mut().expect(\"Stack to never be empty\");\n            last.inc();\n            return *last;\n        }\n        _ => return stack.last().copied().expect(\"Stack to never be empty\"),\n    };\n\n    stack.push(new_context);\n    new_context\n}\n","sourceCodeStart":427,"sourceCodeEnd":460,"githubUrl":"https://github.com/astral-sh/ruff/blob/26f38c119cac42e4d320ba08f09224fdec74af2c/crates/ruff_linter/src/rules/flake8_commas/rules/trailing_commas.rs#L427-L460","documentation":"The flake8-commas trailing-commas rule keeps a stack of bracket contexts while scanning tokens. `update_context` assumes the stack is never empty when a `For` token is processed (e.g. a comprehension's `for` inside brackets); if the stack is empty the invariant is broken and this expect panics.","triggerScenarios":"Running lint (trailing-comma rules COM812/COM818/COM819) on token streams where a `for` token is visited before any opening bracket was pushed — only through an internal scanning bug or unbalanced brackets (e.g. parser producing tokens outside the tracked region).","commonSituations":"Rust contributors modifying token classification; users hitting a crash on specific Python files with unusual bracket/lambda constructs — reported as Ruff crashes rather than user errors.","solutions":["Report the crashing file to Ruff (internal invariant violation)","Upgrade/downgrade Ruff to a version without the crash","Reduce/minimize the Python snippet causing the crash and avoid the construct temporarily (e.g. ignore COM rules for that file)","If developing: guard with `stack.last_mut()` handling empty stacks gracefully"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// treat a panic in linting as a per-file failure and continue\nmatch ruff_lint_file(path) {\n    Ok(diags) => report(diags),\n    Err(e) if e.is_panic() => eprintln!(\"skipped {}: linter crashed ({e})\", path.display()),\n    Err(e) => return Err(e),\n}","preventionTips":["Pin a Ruff version known to pass COM tests on your corpus","Minimize and report any crashing file upstream","Keep COM rules isolated in config so they can be disabled quickly"],"tags":["rust","panic","flake8-commas","token-scanning","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"26f38c119cac42e4d320ba08f09224fdec74af2c","analyzedAt":"2026-09-05T10:32:37.492Z","contentChangedAt":"2026-09-05T10:32:37.492Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}