{"record":{"id":"00ef3e1316f651a8","repo":"astral-sh/ruff","slug":"empty-else-clause","errorCode":null,"errorMessage":"Empty `else` clause","messagePattern":"Empty `else` clause","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"crates/ruff_linter/src/rules/pylint/rules/useless_else_on_loop.rs","lineNumber":141,"sourceCode":"        Stmt::For(ast::StmtFor { orelse, .. }) | Stmt::While(ast::StmtWhile { orelse, .. }) => {\n            loop_exits_early(orelse)\n        }\n        Stmt::Break(_) => true,\n        _ => false,\n    })\n}\n\n/// Generate a [`Fix`] to remove the `else` clause from the given statement.\nfn remove_else(\n    stmt: &Stmt,\n    orelse: &[Stmt],\n    else_range: TextRange,\n    locator: &Locator,\n    indexer: &Indexer,\n    stylist: &Stylist,\n) -> Result<Fix> {\n    let Some(start) = orelse.first() else {\n        return Err(anyhow::anyhow!(\"Empty `else` clause\"));\n    };\n    let Some(end) = orelse.last() else {\n        return Err(anyhow::anyhow!(\"Empty `else` clause\"));\n    };\n\n    let start_indentation = indentation(locator.contents(), start);\n    if start_indentation.is_none() {\n        // Inline `else` block (e.g., `else: x = 1`).\n        Ok(Fix::safe_edit(Edit::deletion(\n            else_range.start(),\n            start.start(),\n        )))\n    } else {\n        // Identify the indentation of the loop itself (e.g., the `while` or `for`).\n        let Some(desired_indentation) = indentation(locator.contents(), stmt) else {\n            return Err(anyhow::anyhow!(\"Compound statement cannot be inlined\"));\n        };\n","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/astral-sh/ruff/blob/26f38c119cac42e4d320ba08f09224fdec74af2c/crates/ruff_linter/src/rules/pylint/rules/useless_else_on_loop.rs#L123-L159","documentation":"An internal guard in the useless-else-on-loop (PLW0120) fix removal path. When deleting a loop's `else` clause, the fixer takes the first and last statements of the `orelse` body to compute the deletion range. If the `else` body is empty (`orelse.first()` is None), there is nothing to remove and the fix aborts with 'Empty `else` clause'.","triggerScenarios":"`remove_else` (called from `useless_else_on_loop`) is invoked with an `orelse` slice whose first statement is None — an `else:` with no body statements reaching the fix stage (normally the diagnostic only fires for non-empty else bodies, so this is a defensive path).","commonSituations":"Rarely hit by end users; mostly surfaced when the rule's fix logic is called with an `else` clause containing only comments/no statements, or by tooling invoking the fix API directly.","solutions":["Treat the Err as 'nothing to fix' and skip the fix","Delete the empty `else:` line manually if it is genuinely useless","Ensure the rule's caller only requests a fix when `orelse` contains at least one statement"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"def has_else_body(orelse: list) -> bool:\n    return len(orelse) > 0","typeGuard":"def has_statements(orelse: list[ast.stmt] | None) -> bool:\n    return bool(orelse)","tryCatchPattern":null,"preventionTips":["Only request the PLW0120 fix when the loop `else` has at least one statement","Filter comment-only else bodies before fix generation"],"tags":["ruff","autofix","pylint","loop","else-clause"],"backgroundTag":"empty-else-clause","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"}