Skip to content

How to Fix and Ignore Ruff Linter Errors in Python Code

I ran ruff check on my Python project and got hit with a wall of errors. Here’s what I saw:

ruff check output
$ uv run ruff check
src/numbers/calculate.py:3:8: F401 [*] `os` imported but unused
src/numbers/calculate.py:7:15: E501 line too long (92 > 88)
src/utils/helpers.py:12:1: F401 [*] `json` imported but unused
src/utils/helpers.py:45:80: E501 line too long (95 > 88)
Found 4 errors.
[*] 2 fixable with the `--fix` option.

I stared at the output. Some errors had that [*] marker, some didn’t. What did that mean? And how was I supposed to deal with all of these?

The Two Types of Errors

The [*] marker is crucial—it tells you Ruff can automatically fix that error. Let me show you the difference:

F401 [*] `os` imported but unused <-- Auto-fixable (remove unused import)
E501 line too long (92 > 88) <-- NOT auto-fixable (requires manual edit)

For auto-fixable errors, Ruff knows exactly what to do. For others, you need to make the call.

My First Mistake: Manually Deleting Imports

I initially opened the file and deleted the unused import myself:

calculate.py (before my manual fix)
from typing import Iterable
import os # I deleted this line manually
def sum_even_numbers(numbers: Iterable[int]) -> int:
...

This worked, but it was tedious. I had 12 files with similar issues. Then I re-read the Ruff output more carefully:

ruff hint in output
[*] 2 fixable with the `--fix` option.

The --fix Flag

Ruff can fix many errors automatically:

auto-fix with ruff
$ uv run ruff check --fix
Found 4 errors (2 fixed, 2 remaining).
src/numbers/calculate.py:7:15: E501 line too long (92 > 88)
src/utils/helpers.py:45:80: E501 line too long (95 > 88)

The two unused imports were removed automatically. The line-too-long errors remain because Ruff can’t know how you want to restructure the code.

Here’s what happened to my file:

calculate.py (after ruff --fix)
from typing import Iterable
def sum_even_numbers(numbers: Iterable[int]) -> int:
...

The import os line is gone. No manual editing required.

When You Can’t Auto-Fix: The noqa Approach

Some errors require your judgment. Take this line:

long line example
result = some_really_long_function_name(first_argument, second_argument, third_argument)

If the line is genuinely long, you have three options:

Option 1: Refactor the code (preferred)

refactored long line
result = some_really_long_function_name(
first_argument,
second_argument,
third_argument
)

Option 2: Inline suppression for specific rule

inline noqa
result = some_really_long_function_name(first_argument, second_argument, third_argument) # noqa: E501

Option 3: File-wide suppression

file-wide noqa
# ruff: noqa: E501
def sum_even_numbers(numbers: Iterable[int]) -> int:
result = some_really_long_function_name(first_argument, second_argument, third_argument)
...

The key difference: # noqa: E501 suppresses for one line, # ruff: noqa: E501 suppresses for the entire file.

My Second Mistake: Using noqa Without a Code

I initially wrote:

wrong noqa usage
import os # noqa

This suppresses ALL rules for that line, not just the unused import. The correct approach:

correct noqa usage
import os # noqa: F401

Always specify the error code. This way, if you later add code that uses os, Ruff will warn you that the suppression is no longer needed.

The --add-noqa Flag: Adding Suppressions Automatically

When you enable a new rule across an existing codebase, you might get dozens of violations. Instead of manually adding # noqa comments, Ruff can do it for you:

add noqa directives automatically
$ uv run ruff check --select UP035 --add-noqa .
Added 3 noqa directives.

This scans your files and adds # noqa: UP035 comments to lines that violate the new rule. It’s useful for gradual adoption of stricter linting.

Here’s what it added:

after --add-noqa
from typing import Iterable # noqa: UP035
def sum_even_numbers(numbers: Iterable[int]) -> int:
...

The UP035 rule warns about deprecated import forms. Adding the suppression lets you continue working while you plan the migration.

Common Ruff Error Codes

Here are the codes I encounter most often:

CodeDescriptionAuto-fixable?
F401Imported but unusedYes
F841Local variable assigned but never usedYes
E501Line too longNo
E712Comparison to True should be is TrueYes
UP035Deprecated import formNo
UP007Use `XY` for type annotations
I001Import block is un-sortedYes

Which Approach to Use When

Error appears
|
v
Is it auto-fixable? (check for [*])
|
+--+--+
| |
Yes No
| |
v v
--fix Is this a legitimate violation?
|
+--+--+
| |
Yes No (it's intentional)
| |
v v
Fix the Add noqa comment
code

Use --fix when: The error is auto-fixable and you agree with the fix.

Use # noqa: CODE when: The violation is intentional or you have a good reason to keep it.

Use # ruff: noqa: CODE when: A specific rule doesn’t apply to the entire file (e.g., line length in generated code).

Use --add-noqa when: You’re adopting a new rule and want to suppress existing violations while enforcing it on new code.

My Workflow Now

  1. Run ruff check to see all errors
  2. Run ruff check --fix to auto-fix what’s possible
  3. Review remaining errors and decide: fix or suppress
  4. For intentional violations, add specific # noqa: CODE comments
  5. For new rules on existing code, use --add-noqa for gradual adoption

This workflow keeps my code clean while giving me control over intentional choices.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments