fixhunt

ruff UP038: tool crashes

tool-crashlabelled unknownprogram-bug · lowduplicate
Findings / 2026-10-17T21-20-52-142Z-httm-ruff-UP038 / r1-p007ruff 0.17.15 → 2 lines2026-10-17 21:20 UTC

Hypothesis Nemotron 3 Super predicted to fire did not fire

If the tuple contains a name from a typing-only import (e.g., List), isinstance(List, ...) may fail at runtime if the import is not present or is TYPE_CHECKING-guarded.

Program

before
1if False:
2 from typing import List as RuntimeList
after
1(no fix applied)

Output

stdout beforeexit 0
(no stdout)
stdout afternot run
(not run)
fired
0 before · 0 after
runs
each version twice, same file name, no network

Judge Nemotron 3 Ultra advisory program-bug · low

The linter crashed because rule UP038 was removed from the codebase and cannot be selected, not because of any rewrite applied to the program. The program itself contains no isinstance or issubclass calls, so the rule would not have matched anything. The observed failure is a tool configuration or version mismatch, not a semantic change from a fix.

Explanation Nemotron 3 Super unverified

The original program defines a conditional import that never executes because its guard is False; thus no name RuntimeList is bound in the module’s namespace. The attempted rewrite does nothing—it leaves the dead code unchanged—but Ruff then crashes because it tries to apply a rule (UP038) that has been removed, so the linter fails before any transformation can occur. Since the tool aborts, the program is not actually rewritten, yet the user observes a failure where none should happen if the rule were applicable. The mismatch arises not from a semantic change in the code but from the tool’s internal state: selecting a non‑existent rule causes a crash, preventing any intended fix from being applied and making the lint process behave incorrectly. This discrepancy between expected safe fixing and actual tool failure explains why the situation is labeled unsafe.

Reproduce

file
prog.py (the before program)
minimized program
r1-p007.py
evidence sheet
r1-p007.md
regression fixture
r1-p007.py the minimized program with a header stating the observed change, for the tool's test suite
python3 prog.py
ruff check --preview --isolated --select UP038 --fix prog.py
python3 prog.py

Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra

UP038 fix · ruff UP038 unused alias · typing import alias removal crash · unused imported name detection

  • related astral-sh/ruff/issues/13051 Existing report is about UP038 documentation being outdated regarding fix safety, not about the rule being removed and causing a crash when selected.
  • related astral-sh/ruff/issues/7871 Existing report is about UP038 rewriting code to be slower and more verbose, not about the rule being removed and causing a crash when selected.
  • duplicate astral-sh/ruff/issues/18349 Existing report describes the same defect: selecting deprecated/removed rule UP038 causes an error/crash instead of a proper warning.

Details

program
Runtime Evaluation of Type Annotations
hazard
If the tuple contains a name from a typing-only import (e.g., List), isinstance(List, ...) may fail at runtime if the import is not present or is TYPE_CHECKING-guarded.
oracle
lint crashed: ruff failed Cause: Rule `UP038` was removed and cannot be selected.
run
2026-10-17T21-20-52-142Z-httm-ruff-UP038
generated program (5 lines) and the fix's diff
1from typing import List
2if False:
3 from typing import List as RuntimeList
4x = [1, 2]
5print(isinstance(x, (List, int)))
rule documentation given to the models
# non-pep604-isinstance (UP038)

Derived from the **pyupgrade** linter.

Fix is always available.

## Removed
This rule was removed as using [PEP 604] syntax in `isinstance` and `issubclass` calls
isn't recommended practice, and it incorrectly suggests that other typing syntaxes like [PEP 695]
would be supported by `isinstance` and `issubclass`. Using the [PEP 604] syntax
is also slightly slower.

## What it does
Checks for uses of `isinstance` and `issubclass` that take a tuple
of types for comparison.

## Why is this bad?
Since Python 3.10, `isinstance` and `issubclass` can be passed a
`|`-separated union of types, which is consistent
with the union operator introduced in [PEP 604].

Note that this results in slower code. Ignore this rule if the
performance of an `isinstance` or `issubclass` check is a
concern, e.g., in a hot loop.

## Example
```python
isinstance(x, (int, float))
```

Use instead:
```python
isinstance(x, int | float)
```

## Options
- `target-version`

## References
- [Python documentation: `isinstance`](https://docs.python.org/3/library/functions.html#isinstance)
- [Python documentation: `issubclass`](https://docs.python.org/3/library/functions.html#issubclass)

[PEP 604]: https://peps.python.org/pep-0604/
[PEP 695]: https://peps.python.org/pep-0695/