ruff Version Drift Fails CI With New Lint Rules
ruff ships new lint rules and tightens existing ones across releases. An unpinned ruff that upgrades between runs can suddenly flag code that passed yesterday - a tooling-version change, not a code change.
What this error means
CI lint fails on rules that were not failing before, with no relevant code change. Comparing ruff --version between the passing and failing runs shows a bump; pinning the old version makes the failures disappear.
app/main.py:12:1: UP045 Use `X | None` instead of `Optional[X]`
Found 7 errors.
# ruff upgraded 0.5.x -> 0.6.x and enabled or changed rulesCommon causes
Unpinned ruff upgraded between runs
Without a pinned version (in requirements/pre-commit), CI installs the latest ruff. A new release’s added or stricter rules flag previously-clean code.
Target version or rule selection drifted
A changed default rule set, or a target-version mismatch, changes which lints apply across ruff releases.
How to fix it
Pin ruff and upgrade deliberately
Pin the exact version in CI and pre-commit so upgrades are intentional and reviewable.
# requirements-dev.txt
ruff==0.6.9
# .pre-commit-config.yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.9Adopt new rules on your terms
When you do upgrade, fix or explicitly select/ignore the new rules rather than letting them fail silently.
ruff check --fix .
# pin rule selection in config
[tool.ruff.lint]
select = ["E", "F", "UP"]How to prevent it
- Pin ruff’s exact version in CI and pre-commit.
- Bump the version in a dedicated change so new rules are reviewed.
- Pin
select/target-versionso rule sets are explicit.