astral-sh/ruff · error
Fix introduced a syntax error
Error message
Fix introduced a syntax error
What it means
After applying an autofix, `lint_fix` re-parses the transformed source. If that parse fails, the fix would have introduced invalid syntax, so Ruff reports a fix syntax error (pointing at the offending fix) and returns this error instead of emitting broken code.
Source
Thrown at crates/ruff_linter/src/linter.rs:639
&suppressions,
);
if iterations == 0 {
has_valid_syntax = parsed.has_valid_syntax();
has_no_syntax_errors = !diagnostics.iter().any(Diagnostic::is_invalid_syntax);
} else {
// If the source code had no syntax errors on the first pass, but
// does on a subsequent pass, then we've introduced a
// syntax error. Return the original code.
if has_valid_syntax && has_no_syntax_errors {
if let Some(error) = parsed.errors().first() {
report_fix_syntax_error(
path,
transformed.source_code(),
error,
fixed.identifiers(),
);
return Err(anyhow!("Fix introduced a syntax error"));
}
}
}
// Apply fix.
if let Some(FixResult {
code: fixed_contents,
fixes: applied,
source_map,
}) = fix_file(&diagnostics, &locator, unsafe_fixes)
{
if iterations < MAX_ITERATIONS {
// Count the number of fixed errors.
for (id, code, count) in applied.iter() {
*fixed.entry(id).or_default(code) += count;
}
transformed = Cow::Owned(transformed.updated(fixed_contents, &source_map));View on GitHub (pinned to 26f38c119c)
Solutions
- Read the `report_fix_syntax_error` output to identify the rule producing the bad fix and disable that rule for the file (e.g. `# ruff: noqa` or per-file-ignores).
- Retry with `--unsafe-fixes` disabled (or vice versa) to avoid the specific fix class.
- Apply fixes rule-by-rule (`--select` one rule at a time) to isolate the interaction.
- If it is a fixer bug, minimize the reproducing file and report it upstream to the Ruff repository.
Example fix
// before $ ruff check --fix --unsafe-fixes module.py # error: Fix introduced a syntax error // after: isolate the offending rule $ ruff check --select RULE_ID module.py # confirm culprit $ ruff check --fix --extend-ignore RULE_ID module.py
Defensive patterns
Strategy: try-catch
Try / catch
match run_ruff_fix(file) {
Err(e) if e.to_string() == "Fix introduced a syntax error" => {
eprintln!("See the report_fix_syntax_error output above; disable the culprit rule and re-run");
// fallback: restore from VCS and fix rule-by-rule
git_checkout(file);
}
other => other?,
} Prevention
- Run `ruff check --fix` only on a clean git working tree so fixes can be reverted.
- Preview fixes with `--diff` before applying.
- Enable unstable/preview fixes in CI only, not on unreviewed code.
- Apply fixes incrementally (one rule group at a time) to isolate bad interactions.
When it happens
Trigger: Running `ruff check --fix` (via `lint_path` or `lint_stdin`) when a rule's generated fix produces source that fails re-parsing, with `report_fix_syntax_error` printing details of the rule and identifiers.
Common situations: Bugs in rule fix implementations, fixes interacting badly when several rules' fixes combine, fixes applied to unusual syntax patterns the fixer didn't anticipate, or usage of unstable/preview fixes.
Related errors
- Unable to rename any references to `{name}`
- 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
AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05).
Data as JSON: /api/errors/8246b0b1403e5a39.
Report an issue: GitHub.