# ruff PLR1736: 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: PLR1736 (tool labels the fix: unknown, this fix reported as safe)
- Oracle: fix-changes-behavior
- Judge (Nemotron 3 Ultra, advisory): real, severity high. The rule assumes the enumerate target is a list and the loop variables are distinct (index, item), so it replaces lst[lst] with lst. In the program the same name lst is used for both variables; the inner lst binds to the element (a string), making the original indexing a TypeError that is caught and printed. After the fix the indexing is removed, the exception disappears, and the program prints nothing — a silent change in observable behavior.
- Program: minimized from 10 to 6 lines

## Reproducer

```python
lst = ['a', 'b', 'c']
for lst, lst in enumerate(lst):  # outer lst shadows inner? actually, first is index, second is element
    try:
        result = lst[lst]  # original: indexes the list with the element (string) -> error
    except Exception as e:
        print(f'{type(e).__name__}: {e}', end=' ')
```

## Commands

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

## Observed

```
stdout before:
TypeError: string indices must be integers, not 'str' TypeError: string indices must be integers, not 'str' TypeError: string indices must be integers, not 'str'
stdout after:
```

## Diff applied by the fix

```diff
--- orig.py	2026-10-22 13:36:02.205629985 -0400
+++ fixed.py	2026-10-22 13:36:04.919675808 -0400
@@ -1,6 +1,6 @@
 lst = ['a', 'b', 'c']
 for lst, lst in enumerate(lst):  # outer lst shadows inner? actually, first is index, second is element
     try:
-        result = lst[lst]  # original: indexes the list with the element (string) -> error
+        result = lst  # original: indexes the list with the element (string) -> error
     except Exception as e:
         print(f'{type(e).__name__}: {e}', end=' ')
```

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

The rewrite replaces `result = lst[lst]` with `result = lst`, changing the operation from indexing the list using its current element (which raises a TypeError because strings cannot index lists) to simply assigning the loop variable itself. This eliminates the exception entirely, so no output is produced where three TypeErrors were previously printed. The behavior differs because the original code intentionally caused and caught errors, while the fix suppresses them by altering the logic inside the try block. Thus, the transformation is not semantics-preserving—it changes what the program does, not just how it expresses it. The label "safe" is incorrect in this context.

## Upstream search

Queries: "PLR1736 fix", "ruff PLR1736 variable shadowing", "enumerate loop duplicate variables", "list indexing with non-integer"

- related: https://github.com/astral-sh/ruff/issues/29422
  umbrella issue listing PLR1736 among many rules but does not describe this specific shadowed-variable construct
- related: https://github.com/astral-sh/ruff/issues/25182
  tracks additional false positives for PLR1736 but focuses on dict iteration, not shadowed loop variables
- related: https://github.com/astral-sh/ruff/issues/12594
  PLR1736 defect about custom start index in enumerate, different construct from shadowed loop variables
- related: https://github.com/astral-sh/ruff/issues/9010
  autofix conflict between PLR1736 and FURB148, different root cause than shadowed-variable rewrite
- duplicate: https://github.com/astral-sh/ruff/issues/8969
  explicitly reports PLR1736 yields invalid suggestion and unsafe fix that changes semantics on shadowed loop variables like `for i, i in enumerate(...)`

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

- [github, open] A few more: missed reports vs flake8/pylint, plus two fix bugs (B012, F402, F823, SIM102, SIM401, PLW1641, PLR1736, PLW0406, N801, UP034) — https://github.com/astral-sh/ruff/issues/29422
- [github, open] Additional false positives in `PLR1733` and `PLR1736` — https://github.com/astral-sh/ruff/issues/25182
- [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] PLR1736 does not account for custom start index — https://github.com/astral-sh/ruff/issues/12594
- [github, closed] Pack of fuzzer Autofix/Infinite loop errors [2] — https://github.com/astral-sh/ruff/issues/8402
- [github, closed] PLR1736 not implemented? — https://github.com/astral-sh/ruff/issues/8972
- [github, closed] Autofix conflict between `PLR1736` and `FURB148` — https://github.com/astral-sh/ruff/issues/9010
- [github, closed] `PLR1736` yields invalid suggestion and unsafe fix that changes semantics. — https://github.com/astral-sh/ruff/issues/8969
- [github, closed] C3001/C3002 Implemented? — https://github.com/astral-sh/ruff/issues/8973
- [github, open] Ruleset Suggestion: wemake-python-styleguide — https://github.com/astral-sh/ruff/issues/3845
- [tavily] Suggestion: Implement Sourcery rules · Issue #11060 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/11060

</details>
