astral-sh/ruff · warning
Expected colon after test
Error message
Expected colon after test
What it means
This error is raised while building the fix for SIM114 (combine `if` branches with identical arms) when the fixer cannot locate the colon after the `if` test of a branch. Without the colon's position, the fixer cannot compute the text range to splice when merging two identical branches, so it aborts the fix.
Source
Thrown at crates/ruff_linter/src/rules/flake8_simplify/rules/if_with_same_arms.rs:122
)
});
}
}
/// Generate a [`Fix`] to merge two [`IfElifBranch`] branches.
fn merge_branches(
stmt_if: &ast::StmtIf,
current_branch: &IfElifBranch,
following_branch: &IfElifBranch,
locator: &Locator,
tokens: &ruff_python_ast::token::Tokens,
) -> Result<Fix> {
// Identify the colon (`:`) at the end of the current branch's test.
let Some(current_branch_colon) =
SimpleTokenizer::starts_at(current_branch.test.end(), locator.contents())
.find(|token| token.kind == SimpleTokenKind::Colon)
else {
return Err(anyhow::anyhow!("Expected colon after test"));
};
let deletion_edit = Edit::deletion(
locator.full_line_end(current_branch.end()),
locator.full_line_end(following_branch.end()),
);
// If the following test isn't parenthesized, consider parenthesizing it.
let following_branch_test = if let Some(range) =
parenthesized_range(following_branch.test.into(), stmt_if.into(), tokens)
{
Cow::Borrowed(locator.slice(range))
} else if matches!(
following_branch.test,
Expr::Lambda(_) | Expr::Named(_) | Expr::If(_)
) {
// If the following expressions binds more tightly than `or`, parenthesize it.
Cow::Owned(format!("({})", locator.slice(following_branch.test)))View on GitHub (pinned to 26f38c119c)
Solutions
- Reformat the `if`/`elif` statements so the test expression ends with a normal `:` and rerun the fix
- Manually merge the identical branches by replacing `elif` with `or` or deleting the duplicate branch
- Report a reproducing snippet upstream so the fixer can be made robust
Example fix
# before (two identical branches)
if x == 1:
do()
elif x == 2:
do()
# after (combined)
if x in (1, 2):
do() Defensive patterns
Strategy: try-catch
Try / catch
let fix = merge_branches(...).unwrap_or_else(|_| {
// emit diagnostic without fix; log "Expected colon after test"
Fix::empty()
}); Prevention
- Format `if`/`elif` tests with a normal trailing `:`
- Avoid exotic token layouts around branch headers
- Treat SIM114 fixes as best-effort and always keep a no-fix fallback
When it happens
Trigger: `merge_branches` scans the locator's contents from the branch's test expression to find a colon token; if the token at the expected end position of the test is not a Colon (unexpected token layout in the parsed source), the fix returns Err('Expected colon after test').
Common situations: Autofixing `if/elif` chains with identical bodies where the source has irregular token layout; seen by users of `ruff --fix` as an unfixed diagnostic or by plugin/test developers consuming the fix API.
Related errors
- Failed to collapse `with`: {err}
- Unable to fix multiline statement
- Expected indented block to have at least one statement
- Expected outer with to have indented body
- Expected one inner with statement
AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05).
Data as JSON: /api/errors/5476548d8afb006c.
Report an issue: GitHub.