# ruff W605: fix changes program behavior

Internal evidence sheet generated by fixhunt. Not an issue text. A human re-verifies, checks the duplicates
below, and writes the upstream report in their own words following the project's AI policy.

- Tool: ruff ruff 0.17.1
- Rule: W605 (tool labels the fix: unknown, this fix reported as safe)
- Oracle: fix-changes-behavior
- Judge (Nemotron 3 Ultra, advisory): intended-change, severity low. The rule rewrites the string literal to a raw string to eliminate the SyntaxWarning about the invalid escape sequence '\_'. The stderr difference (warning disappears) is exactly the semantic change the rule documents as its purpose.
- Program: minimized from 7 to 2 lines

## Reproducer

```python
with open('test.txt', 'w') as f:
    f.write('\_')
```

## Commands

```sh
python3 prog.py
ruff check --preview --isolated --select W605 --fix prog.py
python3 prog.py
```

## Observed

```
stderr before: /w/prog.py:2: SyntaxWarning: invalid escape sequence '\_'
stderr after: (none)
```

## Diff applied by the fix

```diff
--- orig.py	2026-10-22 13:32:50.944406964 -0400
+++ fixed.py	2026-10-22 13:32:53.049442361 -0400
@@ -1,2 +1,2 @@
 with open('test.txt', 'w') as f:
-    f.write('\_')
+    f.write(r'\_')
```

## Why the rewrite is not equivalent (model draft, verify before use)

The original string literal '\\_' contains a backslash followed by underscore; Python interprets this as an invalid escape sequence, issuing a SyntaxWarning but treating it as two characters: backslash then underscore. After rewriting to r'\\_', the raw string literal disables escape processing, so the backslash remains a literal character and the underscore is literal—still two characters—but now no warning is emitted. Although the resulting file content is identical, the program’s behavior differs because the SyntaxWarning is suppressed, altering diagnostic output. Since the fix changes whether a warning is produced, it is not semantics‑preserving under Ruff’s definition of safety, which requires identical observable behavior including warnings. Thus labeling the fix safe is incorrect.

## Upstream search

Queries: "W605 fix", "W605 invalid escape sequence", "write backslash underscore warning", "raw string literal fix"

- related: https://github.com/astral-sh/ruff/issues/11491
  Same rule W605 but different construct (f-string vs regular string literal)
- related: https://github.com/astral-sh/ruff/issues/8616
  Mentions W605 fixer creating unnecessary escapes, same rule but different context
- related: https://github.com/astral-sh/ruff/issues/19655
  Interaction between W605 and ISC002 making W605 unfixable, same rule but different defect
- duplicate: https://github.com/astral-sh/ruff/issues/11461
  Same rule W605, same fix strategy (raw string), same defect class of unsafe fix changing behavior
- related: https://github.com/astral-sh/ruff/issues/10434
  W605 causing panic on f-string with escapes, same rule but different trigger
- related: https://github.com/astral-sh/ruff/issues/6987
  W605 autofix error with ANN401, same rule but different construct
- related: https://github.com/astral-sh/ruff/issues/5061
  Feature request to use raw strings for W605 fix, same rule and fix strategy but not a bug report
- related: https://github.com/astral-sh/ruff/issues/19543
  Question about W605 on byte strings, same rule but different string type
- related: https://github.com/astral-sh/ruff/issues/20196
  About emitting all CPython SyntaxWarnings including W605, same rule but broader scope
- related: https://github.com/astral-sh/ruff/issues/12165
  W605 causing panic on specific file, same rule but different trigger
- related: https://github.com/astral-sh/ruff/issues/474
  Original implementation issue for W605, same rule but not the same fix defect
- related: https://github.com/astral-sh/ruff/issues/8617
  Q000 fixer not removing obsolete backslash escapes after quote change, same domain but different rule
- related: https://github.com/astral-sh/ruff/issues/18816
  PLE2510 fix causing syntax error in f-strings with escapes, similar domain but different rule
- related: https://github.com/astral-sh/ruff/issues/14555
  UP031 undesirable in raw strings/regex, related to raw string usage but different rule
- related: https://github.com/astral-sh/ruff/issues/12391
  D301 autofix doubling escaped backslashes in docstrings, similar fix domain but different rule

<details><summary>All hits</summary>

- [github, open] Wrong fix for W605 in f-strings — https://github.com/astral-sh/ruff/issues/11491
- [github, open] Implement remaining `pycodestyle` rules — https://github.com/astral-sh/ruff/issues/2402
- [github, open] Include some of the checks from flake8-literal — https://github.com/astral-sh/ruff/issues/8616
- [github, closed] unused-function-argument not silenced by prefixed underscore if variable name is "次" — https://github.com/astral-sh/ruff/issues/28721
- [github, open] Implement Pylint — https://github.com/astral-sh/ruff/issues/970
- [github, closed] ISC002 makes W605 unfixable on playground — https://github.com/astral-sh/ruff/issues/19655
- [github, closed] W605 fix is unsafe — https://github.com/astral-sh/ruff/issues/11461
- [github, closed] Ruff does not clean up unused import if it has same name like object attribute — https://github.com/astral-sh/ruff/issues/12775
- [github, closed] Pack of fuzzer Autofix/Infinite loop errors [2] — https://github.com/astral-sh/ruff/issues/8402
- [github, closed] Rule W605 cause panic — https://github.com/astral-sh/ruff/issues/10434
- [tavily] Rules ANN401,W605 cause autofix error · Issue #6987 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/6987
- [tavily] Change W605 autofix to use raw strings if possible · Issue #5061 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/5061
- [github, open] Should W605 flag certain byte string escapes? — https://github.com/astral-sh/ruff/issues/19543
- [github, open] Rule suggestion: Emit warning for continuation characters in multi-line strings — https://github.com/astral-sh/ruff/issues/7359
- [github, open] Ruff should warn on all CPython SyntaxWarnings — https://github.com/astral-sh/ruff/issues/20196
- [github, open] Validation for ruff config file — https://github.com/astral-sh/ruff/issues/10487
- [github, closed] Checking file with rule W605 cause panic — https://github.com/astral-sh/ruff/issues/12165
- [tavily] Implement W605, invalid escape sequence · Issue #474 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/474
- [tavily] Tests using fixtures prefixed with underscore (_) are flagged as violating PT019 · Issue #18119 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/18119
- [tavily] Q000 fixer does not remove obsolete backslash-escape inside string after changing quotes · Issue #8617 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/8617
- [tavily] Get python version from environment · Issue #769 · astral-sh/ruff-vscode · GitHub — https://github.com/astral-sh/ruff-vscode/issues/769
- [tavily] `start_of_file` handles at most one backslash, making I002 introduce a syntax error · Issue #19815 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/19815
- [tavily] Emit a warning instead of an error for unknown rule selectors by ntBre · Pull Request #26113 · astral-sh/ruff · GitHub — https://redirect.github.com/astral-sh/ruff/pull/26113
- [tavily] [`Pylint`] `PLE2510` fix causes syntax error inside pre-3.12 f-strings · Issue #18816 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/18816
- [github, open] Raw strings break the FLY002 fix — https://github.com/astral-sh/ruff/issues/21082
- [github, open] `UP032` fix fails when braces are created via escapes — https://github.com/astral-sh/ruff/issues/19792
- [github, open] RUF039 fix should be available for octal escapes and `u` string prefixes — https://github.com/astral-sh/ruff/issues/19707
- [github, open] Feature request: Option to use lowercase hex literals — https://github.com/astral-sh/ruff/issues/10432
- [github, open] UP031 may be undesirable in raw strings and regular expressions — https://github.com/astral-sh/ruff/issues/14555
- [github, open] D301 autofix doubles escaped backslashes — https://github.com/astral-sh/ruff/issues/12391
- [github, open] Only emit RUF039 for strings that actually require escaping — https://github.com/astral-sh/ruff/issues/18795
- [github, open] Possibility to implement flake8-length into ruff — https://github.com/astral-sh/ruff/issues/4595

</details>
