# 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 r'\_' to eliminate the SyntaxWarning about an invalid escape sequence. The observed difference is the disappearance of that warning, which is exactly the semantic change the rule documents as its purpose.
- Program: minimized from 13 to 11 lines

## Reproducer

```python
class Logger:
    def __init__(self):
        self.buf = []
    def write(self, msg):
        self.buf.append(msg)
    def __enter__(self):
        return self
    def __exit__(self, *args):
        pass
with Logger() as log:
    log.write('\_')
```

## Commands

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

## Observed

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

## Diff applied by the fix

```diff
--- orig.py	2026-10-22 13:32:26.680999093 -0400
+++ fixed.py	2026-10-22 13:32:28.850035544 -0400
@@ -8,4 +8,4 @@
     def __exit__(self, *args):
         pass
 with Logger() as log:
-    log.write('\_')
+    log.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 the backslash as a literal character, so the stored value is the two‑character string '\\_'. The rewritten literal r'\\_' is a raw string where backslashes are not escape characters, so it also stores the two‑character string '\\_'. Although the resulting string content is identical, the original code produced a SyntaxWarning on compilation, while the fixed version suppresses that warning. Since the presence or absence of a warning constitutes observable differing behavior, the transformation is not semantics‑preserving.

## Upstream search

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

- related: https://github.com/astral-sh/ruff/issues/11491
  Same rule W605 but different construct (f-string vs regular string)
- duplicate: https://github.com/astral-sh/ruff/issues/11461
  Same rule W605, same raw-string autofix making invalid escape sequences valid (changing behavior)
- related: https://github.com/astral-sh/ruff/issues/5061
  Feature request to use raw strings for W605 fix, which is what the new finding demonstrates as unsafe

<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
- [github, open] Feature: Port Sonar's Python scanner checks — https://github.com/astral-sh/ruff/issues/4935

</details>
