{"record":{"id":"63e0ef8896227a17","repo":"astral-sh/ruff","slug":"else-is-expected-to-be-on-its-own-line","errorCode":null,"errorMessage":"`else` is expected to be on its own line","messagePattern":"`else` is expected to be on its own line","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/ruff_linter/src/rules/pylint/rules/collapsible_else_if.rs","lineNumber":119,"sourceCode":"\n/// Generate [`Fix`] to convert an `else` block to an `elif` block.\nfn convert_to_elif(\n    first: &Stmt,\n    else_clause: &ElifElseClause,\n    locator: &Locator,\n    indexer: &Indexer,\n    stylist: &Stylist,\n) -> Result<Fix> {\n    let inner_if_line_start = locator.line_start(first.start());\n    let inner_if_line_end = locator.line_end(first.end());\n\n    // Capture the trivia between the `else` and the `if`.\n    let else_line_end = locator.full_line_end(else_clause.start());\n    let trivia_range = TextRange::new(else_line_end, inner_if_line_start);\n\n    // Identify the indentation of the outer clause\n    let Some(indentation) = indentation(locator.contents(), else_clause) else {\n        return Err(anyhow::anyhow!(\"`else` is expected to be on its own line\"));\n    };\n\n    // Dedent the content from the end of the `else` to the end of the `if`.\n    let indented = adjust_indentation(\n        TextRange::new(inner_if_line_start, inner_if_line_end),\n        indentation,\n        locator,\n        indexer,\n        stylist,\n    )?;\n\n    // If there's trivia, restore it\n    let trivia = if trivia_range.is_empty() {\n        None\n    } else {\n        let indented_trivia =\n            adjust_indentation(trivia_range, indentation, locator, indexer, stylist)?;\n        Some(Edit::insertion(","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/astral-sh/ruff/blob/26f38c119cac42e4d320ba08f09224fdec74af2c/crates/ruff_linter/src/rules/pylint/rules/collapsible_else_if.rs#L101-L137","documentation":"This is a fix-generation failure in pylint's collapsible-else-if (PLR5501) fix, which rewrites an `else: if ...` block into an `elif`. The fixer needs the indentation of the `else` clause to dedent the inner `if` correctly; Ruff's `indentation()` returns None for clauses not starting on their own line, so the fix aborts with this message.","triggerScenarios":"`convert_to_elif` (called from `collapsible_else_if`) encounters a nested `if` inside an `else:` where the `else` keyword is not on its own line (e.g. `else: if cond:` on one line) or its indentation cannot be detected (mixed tabs, unusual layout).","commonSituations":"Autofixing compact one-line `else: if ...` code, generated or minified Python, or files mixing tabs and spaces; users of `ruff --fix` see PLR5501 reported but not fixed.","solutions":["Put `else:` on its own line with standard indentation, keeping the nested `if` on the next line, then rerun the fix","Manually rewrite the nested `else: if` into an `elif`","Normalize tabs to spaces (or configure Ruff's indentation settings) so indentation detection succeeds"],"exampleFix":"# before (fix fails)\nif a:\n    f()\nelse: if b:\n    g()\n# after\nif a:\n    f()\nelif b:\n    g()","handlingStrategy":"validation","validationCode":"import re\ndef elif_fix_candidate(source: str) -> bool:\n    # else must be alone on its line, consistently indented\n    return re.search(r\"^\\s*else:\\s*$\", source, re.M) is not None","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never write `else: if ...` on one line","Use a single indentation style (spaces) throughout the file","Run `ruff format` before `ruff --fix`"],"tags":["ruff","autofix","pylint","indentation","elif"],"backgroundTag":"autofix-indentation-detection-failed","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"}