astral-sh/ruff · info
Expected one inner if statement
Error message
Expected one inner if statement
What it means
After matching the outer `if`, the collapse requires its indented body to contain exactly one statement and that statement to be a plain `if` without `orelse`. Anything else (multiple statements, an `elif`/`else` on the inner node, other compound statements) bails with this message, since `if a: if b:` can only merge when the inner body is a single guard `if`.
Source
Thrown at crates/ruff_linter/src/rules/flake8_simplify/rules/collapsible_if.rs:377
let outer_if = match_if(statement)?;
let libcst_native::If {
body: libcst_native::Suite::IndentedBlock(outer_body),
orelse: None,
..
} = outer_if
else {
bail!("Expected outer if to have indented body and no else")
};
let [
libcst_native::Statement::Compound(libcst_native::CompoundStatement::If(
inner_if @ libcst_native::If { orelse: None, .. },
)),
] = &mut *outer_body.body
else {
bail!("Expected one inner if statement");
};
outer_if.test =
libcst_native::Expression::BooleanOperation(Box::new(libcst_native::BooleanOperation {
left: Box::new(parenthesize_and_operand(outer_if.test.clone())),
operator: libcst_native::BooleanOp::And {
whitespace_before: space(),
whitespace_after: space(),
},
right: Box::new(parenthesize_and_operand(inner_if.test.clone())),
lpar: vec![],
rpar: vec![],
}));
outer_if.body = inner_if.body.clone();
// Reconstruct and reformat the code.
let module_text = tree.codegen_stylist(stylist);
let module_text = if outer_indent.is_empty() {View on GitHub (pinned to 15f3fe6b15)
Solutions
- Move any extra statements out of the outer body (or merge them into the innermost block) so only the inner `if` remains, then rerun the fix
- Manually combine conditions into `if a and b:` when restructuring by hand
- Add `# noqa: SIM102` if the multi-statement nesting is intentional
Example fix
// before
if a:
setup()
if b:
do()
// after
setup_ok = not a or False # or restructure:
if a and b:
do() Defensive patterns
Strategy: validation
Validate before calling
python - <<'EOF'
import ast, sys
tree = ast.parse(open(sys.argv[1]).read())
for n in ast.walk(tree):
if isinstance(n, ast.If) and len(n.body) == 1 and isinstance(n.body[0], ast.If):
inner = n.body[0]
if not (len(inner.body) >= 1 and not inner.orelse) or not n.orelse:
pass
if inner.orelse or len(n.body) != 1:
print('not a single plain inner if at line', inner.lineno)
EOF Prevention
- Keep the outer block containing exactly the inner `if` when you intend a collapsible guard
- Move side-effect statements out of the outer guard body
- Use `# noqa: SIM102` for deliberate multi-statement nesting instead of expecting a fix
When it happens
Trigger: `ruff check --fix` on an outer `if` whose body holds several statements before/after the inner `if`, or the inner `if` has its own `else`/`elif`.
Common situations: Nested guards with trailing statements (`if a: x = 1; if b: ...` on separate lines), inner `if` with `else`, bodies mixing simple and compound statements.
Related errors
- Failed to collapse `if`: {err}
- Expected indented block to have at least one statement
- Failed to collapse `with`: {err}
- Unable to fix multiline statement
- Expected indented block to have at least one statement
AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-09-05).
Data as JSON: /api/errors/da41eb63299b9412.
Report an issue: GitHub.