2025, Sep 27 01:00
Why Flake8 Flags Only Some Missing Spaces: Understanding E226 vs E225 and pycodestyle Behavior
Learn why Flake8 flags fully unspaced operators with E226 while partial cases fall under E225. See how pycodestyle drives this and configure consistent checks.
Why does Flake8 flag only some missing spaces around arithmetic operators while letting others slip through? If you have ever seen E226 appear on one line and not on another that looks equally suspect, you are running into a subtle split in how style checks are delegated under the hood.
Minimal example of the discrepancy
The following snippet shows three visually similar expressions, but only one is flagged by Flake8 for E226 when E225 is ignored:
x = 0*0  # flagged as E226
x = 0* 0  # not flagged as E226 when E225 is ignored
x = 0 *0  # not flagged as E226 when E225 is ignored
According to commonly referenced guidance, the expected behavior sounds straightforward:
There should be one space before and after an arithmetic operator (+, -, /, and *).
What’s actually happening
The behavior comes from pycodestyle, not from Flake8 itself. Flake8 acts as a wrapper and delegates style checks to pycodestyle. Inside pycodestyle.py, the rule E226 “missing whitespace around arithmetic operator” is implemented with branching that tracks an internal state (for example, via variables like need_space). That branching influences whether E226 or E225 gets raised in different spacing scenarios.
In short, E226 targets an arithmetic operator with no spaces on either side, which matches the first line. The other two lines fall under E225, which covers missing whitespace around an operator in other situations. If E225 is on your ignore list, only the first line is reported as E226, and the other two lines are skipped.
References: pycodestyle implementation (pycodestyle Github) and the E225/E226 rule descriptions (E225 Rule, E226 Rule).
How to make the linter behavior consistent
If you want all three lines to be flagged, do not ignore E225. When E225 is enabled, it will cover the partially spaced cases, and E226 will continue to cover the fully unspaced arithmetic operator. In practice this means enabling both E225 and E226 so that all spacing violations are surfaced.
Corrected code
To comply with the guidance, use one space on both sides of the operator:
y = 0 * 0
There is an additional nuance: E226 depends on context. pep8 suggests using whitespace to highlight operator precedence, for example, y = m*x + c is preferred over y = m * x + c. This explains why E226 and E225 exist as separate checks and why they behave slightly differently.
Why this matters for your tooling
Understanding that Flake8 delegates to pycodestyle clarifies why changing Flake8 options alone can lead to seemingly inconsistent results. Knowing the split responsibilities of E225 and E226 helps you configure your ignore list and CI gates without surprises, and it prevents code reviews from getting stuck on what looks like a linter glitch.
Takeaways
If you see only the fully unspaced operator being flagged, it is because E226 covers that exact case, while partial spacing issues fall under E225. Enable both E225 and E226 for comprehensive whitespace checks, format arithmetic operators with a space on both sides when appropriate, and keep in mind that E226 may allow context-driven spacing choices to express precedence.
The article is based on a question from StackOverflow by ginjaemocoes and an answer by David Silveiro.