astral-sh/ruff · error
Cannot find `:` in `else` statement
Error message
Cannot find `:` in `else` statement
What it means
Internal guard in Ruff's fixer for flake8-return rules (RET505 `superfluous-else-return` and siblings). When inlining an `else:` clause, `remove_else` tokenizes source starting at the `else` keyword to locate the colon that terminates the `else` header. If the tokenizer reaches the end of the token stream without a `Colon`, fix construction is aborted; the diagnostic is still reported, just without an autofix.
Source
Thrown at crates/ruff_linter/src/rules/flake8_return/rules/function.rs:836
if elif_else.test.is_some() {
// Ex) `elif` -> `if`
Ok(Fix::safe_edit(Edit::deletion(
elif_else.start(),
elif_else.start() + TextSize::from(2),
)))
} else {
// the start of the line where the `else`` is
let else_line_start = locator.line_start(elif_else.start());
// making a tokenizer to find the Colon for the `else`, not always on the same line!
let mut else_line_tokenizer =
SimpleTokenizer::starts_at(elif_else.start(), locator.contents());
// find the Colon for the `else`
let Some(else_colon) =
else_line_tokenizer.find(|token| token.kind == SimpleTokenKind::Colon)
else {
return Err(anyhow::anyhow!("Cannot find `:` in `else` statement"));
};
// get the indentation of the `else`, since that is the indent level we want to end with
let Some(desired_indentation) = indentation(locator.contents(), elif_else) else {
return Err(anyhow::anyhow!("Compound statement cannot be inlined"));
};
// If the statement is on the same line as the `else`, just remove the `else: `.
// Ex) `else: return True` -> `return True`
if let Some(first) = elif_else.body.first() {
if indexer.preceded_by_multi_statement_line(first, locator.contents()) {
return Ok(Fix::safe_edit(Edit::deletion(
elif_else.start(),
first.start(),
)));
}
}
View on GitHub (pinned to 26f38c119c)
Solutions
- Reformat the `if/else` normally (colon directly after `else`) and re-run `ruff --fix`.
- Minimize with `ruff check --isolated --fix path/to/file.py`; if it persists on valid input, file a bug at https://github.com/astral-sh/ruff — this is an internal invariant failure, not user error.
- Work around by disabling the triggering RET rule (e.g. `lint.ignore = ["RET505"]`) or fixing the code manually.
- Update Ruff to the latest version; tokenizer edge cases are fixed regularly.
Example fix
// before (edge-case layout that stalls the fixer)
if cond:
return a
else \
: return b
// after (normal layout the fixer handles)
if cond:
return a
else:
return b Defensive patterns
Strategy: try-catch
Validate before calling
import re
def else_clause_is_fixable(source: str) -> bool:
# a normal `else:` header on its own line is safe to autofix
return bool(re.search(r'^[ \t]*else[ \t]*:[ \t]*', source, re.MULTILINE)) Type guard
def has_plain_else_colon(source: str) -> bool:
return any(line.lstrip().startswith('else:') for line in source.splitlines()) Try / catch
try:
subprocess.run(['ruff', 'check', '--fix', '--select', 'RET505', path], check=True)
except subprocess.CalledProcessError:
print(f'autofix failed for {path}; reformat else: headers manually and retry') Prevention
- Keep `else:` headers on their own line with the colon immediately after the keyword.
- Run `ruff check --no-fix` first; report any RET505 hit without a fix upstream as a bug.
- Pin and regularly update Ruff; tokenizer edge cases get fixed over time.
- Scope RET505-RET508 autofixes to directories with conventionally formatted code.
When it happens
Trigger: `remove_else` (via `superfluous_else_node`) invoked on an `else` clause whose header colon cannot be found by `SimpleTokenizer::starts_at(elif_else.start(), ...)` — e.g. unusual source layout where `else` is not followed by a colon token in the linear stream.
Common situations: Applying `ruff --fix` to RET505-RET508 hits with exotic but parseable formatting or generated code; a Ruff parser/tokenizer or `ElifElseClause` range edge case; `else` keywords in unexpected positions such as line continuations.
Related errors
- Fix introduced a syntax error
- Unable to rename any references to `{name}`
- Compound statement cannot be inlined
- Positional argument {index} is missing
- Expected dictionary argument to be kwarg
AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05).
Data as JSON: /api/errors/9f31d14dd1e3f328.
Report an issue: GitHub.