astral-sh/ruff · info
Expected indented block to have at least one statement
Error message
Expected indented block to have at least one statement
What it means
During the SIM102 collapse, the outer body is temporarily embedded in a function definition so libcst exposes an `IndentedBlock`; if that block has no statements (`body.first_mut()` is `None`) the fix bails, since a merged `if` needs at least one statement to move under it.
Source
Thrown at crates/ruff_linter/src/rules/flake8_simplify/rules/collapsible_if.rs:355
Cow::Owned(format!(
"def f():{}{module_text}",
stylist.line_ending().as_str()
))
};
// Parse the CST.
let mut tree = match_statement(&module_text)?;
let statement = if outer_indent.is_empty() {
&mut tree
} else {
let embedding = match_function_def(&mut tree)?;
let indented_block = match_indented_block(&mut embedding.body)?;
indented_block.indent = Some(outer_indent);
let Some(statement) = indented_block.body.first_mut() else {
bail!("Expected indented block to have at least one statement")
};
statement
};
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, .. },View on GitHub (pinned to 15f3fe6b15)
Solutions
- Ensure the innermost `if` body contains at least one statement (e.g. add `pass` or the real body) and rerun the fix
- Collapse the conditions manually into a single `if a and b:`
- Suppress SIM102 with `# noqa` until the body is filled in
Example fix
// before
if a:
if b:
pass # only statement
// after
if a and b:
pass 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 len(inner.body) == 0:
print('empty nested-if body at line', inner.lineno, '- not SIM102-fixable')
EOF Prevention
- Never commit empty `if` bodies; use `pass` explicitly or fill in the real body first
- Check for blocks containing only comments before running SIM102 autofixes
- Run autofixes after tests pass so partial/broken bodies don't reach the linter
When it happens
Trigger: A nested `if a: if b:` where the innermost body is empty or unparseable into a first statement — practically `if` blocks containing only comments or pass-less bodies produced by partial edits.
Common situations: Work-in-progress code with empty blocks, code stripped by other tools leaving only comments, or stub files.
Related errors
- Failed to collapse `if`: {err}
- Expected one inner if 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/21a791c772adde2f.
Report an issue: GitHub.