astral-sh/ruff · error

Failed to fix invalid comparison: {node:?}

Error message

Failed to fix invalid comparison: {node:?}

What it means

Ruff's F632 (is-literal comparison) autofix replaces `is`/`is not` with `==`/`!=` for literal comparisons. This bail fires when the located comparison operator node is neither `Is` nor `IsNot`, meaning the cached operator no longer matches the fix's expectation, so no safe replacement exists.

Source

Thrown at crates/ruff_linter/src/rules/pyflakes/rules/invalid_literal_comparisons.rs:102

                || helpers::is_constant_non_singleton(right)
                || helpers::is_mutable_iterable_initializer(left)
                || helpers::is_mutable_iterable_initializer(right))
        {
            let mut diagnostic =
                checker.report_diagnostic(IsLiteral { cmp_op: op.into() }, compare.range());
            if lazy_located.is_none() {
                lazy_located = Some(locate_cmp_ops(compare.range(), checker.tokens()));
            }
            diagnostic.try_set_optional_fix(|| {
                if let Some(located_op) =
                    lazy_located.as_ref().and_then(|located| located.get(index))
                {
                    assert_eq!(located_op.op, *op);
                    if let Ok(content) = match located_op.op {
                        CmpOp::Is => Ok::<String, Error>("==".to_string()),
                        CmpOp::IsNot => Ok("!=".to_string()),
                        node => {
                            bail!("Failed to fix invalid comparison: {node:?}")
                        }
                    } {
                        Ok(Some(Fix::safe_edit(Edit::range_replacement(
                            content,
                            located_op.range,
                        ))))
                    } else {
                        Ok(None)
                    }
                } else {
                    bail!("Failed to fix invalid comparison due to missing op")
                }
            });
        }
    }
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]

View on GitHub (pinned to 15f3fe6b15)

Solutions

  1. Update Ruff to the latest release
  2. Replace `is`/`is not` with `==`/`!=` manually for the literal comparison
  3. Suppress F632 with a `# noqa: F632` comment if the identity check is intentional

Example fix

# before
if x is None or y is not 0:
    pass
# after
if x == None or y != 0:
    pass  # better: `if x is None or y != 0:` with a real literal comparison fixed as ==/!=
Defensive patterns

Strategy: validation

Validate before calling

# Check comparisons before relying on the fix:
if x is 'literal':  # F632 flagged; fixer replaces `is` with `==`
    ...

Prevention

When it happens

Trigger: `invalid_literal_comparison` recorded an operator range, then while building the fix the `CmpOp` at that node matched neither `CmpOp::Is` nor `CmpOp::IsNot` — an internal invariant violation between diagnostic collection and fix generation.

Common situations: Effectively unreachable in released versions; may appear with patched/modified Ruff builds or mid-version AST changes over unusual comparison chains.

Related errors


AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-09-05). Data as JSON: /api/errors/3d656094c3ccd507. Report an issue: GitHub.