astral-sh/ruff · error

Expected one inner with statement

Error message

Expected one inner with statement

What it means

This completes the SIM117 fix: the outer `with` must contain exactly one inner `with` statement so the two context lists can be merged. If the outer body holds zero or multiple statements, or the first statement isn't a `with`, the merge cannot proceed and the fixer bails.

Source

Thrown at crates/ruff_linter/src/rules/flake8_simplify/rules/fix_with.rs:66

        let Some(statement) = indented_block.body.first_mut() else {
            bail!("Expected indented block to have at least one statement")
        };
        statement
    };

    let outer_with = match_with(statement)?;

    let With {
        body: Suite::IndentedBlock(outer_body),
        ..
    } = outer_with
    else {
        bail!("Expected outer with to have indented body")
    };

    let [Statement::Compound(CompoundStatement::With(inner_with))] = &mut *outer_body.body else {
        bail!("Expected one inner with statement");
    };

    outer_with.items.append(&mut inner_with.items);
    if outer_with.lpar.is_none() {
        outer_with.lpar.clone_from(&inner_with.lpar);
        outer_with.rpar.clone_from(&inner_with.rpar);
    }
    outer_with.body = inner_with.body.clone();

    // Reconstruct and reformat the code.
    let module_text = tree.codegen_stylist(stylist);
    let contents = if outer_indent.is_empty() {
        module_text
    } else {
        module_text
            .strip_prefix(&format!("def f():{}", stylist.line_ending().as_str()))
            .unwrap()
            .to_string()

View on GitHub (pinned to 26f38c119c)

Solutions

  1. Manually merge the nested `with` statements into one: `with a as x, b as y:`
  2. Ensure the inner block contains only the single inner `with` if you want the autofix to apply
  3. Ignore SIM117 via noqa or configuration if the structure is intentional

Example fix

// before (fixer cannot merge: extra statement inside outer with)
with open('a') as a:
    log(a)
    with open('b') as b:
        use(a, b)
// after
with open('a') as a, open('b') as b:
    use(a, b)
Defensive patterns

Strategy: fallback

Validate before calling

// Autofix only applies when the outer `with` body is exactly one inner `with`:
# ensure: with X:
#             with Y:
#                 body

Prevention

When it happens

Trigger: The outer `with`'s indented body contains anything other than exactly one compound `With` statement — e.g. multiple statements, a non-with statement, or a trailing comment parsed as a body element — while running the SIM117 autofix.

Common situations: Nested `with` blocks that contain additional statements inside the outer context, code with interleaved comments or `pass` lines between the two `with` statements, or partially refactored code.

Related errors


AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05). Data as JSON: /api/errors/66613038c0572ef8. Report an issue: GitHub.