ruff / flake8 Lint Failures Breaking CI - Fix or Configure
A linter exited non-zero because it found violations. Often they are real and should be fixed; sometimes CI fails where local passes because the linter version or config differs between environments.
What this error means
A ruff check or flake8 step fails with a list of CODE violations and exit code 1, while the same code may pass locally on a different linter version or with a different config picked up.
app/main.py:10:1: F401 'os' imported but unused
app/main.py:22:80: E501 line too long (94 > 79 characters)
Found 2 errors.Common causes
Real lint violations
Unused imports (F401), long lines (E501), undefined names (F821) and similar are genuine issues the linter is flagging.
Version/config drift between local and CI
CI installs a different linter version, or reads a different config file, so a rule fires in CI that did not locally - a false "works on my machine."
How to fix it
Auto-fix and review what remains
ruff can fix many issues; review and address the rest.
ruff check --fix .
ruff format .
ruff check . # confirm cleanPin the linter and centralize config
- Pin the exact ruff/flake8 version in dev deps (and pre-commit) so local and CI match.
- Keep one config (
pyproject.toml/ruff.toml/.flake8) at the repo root. - Configure or
# noqa: CODEspecific intentional exceptions instead of disabling rules broadly.
How to prevent it
- Pin linter versions so local and CI agree.
- Run ruff/flake8 in pre-commit to catch issues before pushing.
- Keep a single root config and scope ignores narrowly.