If Python reports TabError: inconsistent use of tabs and spaces in indentation, one block of your code is indented with both tabs and spaces, and the interpreter cannot tell how deeply nested the line is. The fix is not rewriting code — it is two editor actions: turn on whitespace rendering, then convert the file to spaces (VS Code: Convert Indentation to Spaces; PyCharm: Edit → Convert Indents → To Spaces).
Below: why the file looked aligned, how TabError differs from the two IndentationError messages people confuse it with, and which settings keep it away.
What does Python TabError inconsistent use of tabs and spaces mean?
TabError is Python refusing to guess. Indentation defines nesting, so the interpreter must know whether the current line is deeper than the previous one. If one line is indented with four spaces and the next with a tab, the answer depends on whether a tab counts as four columns or eight. Python will not pick for you — it stops before running a single statement.
A discount function: three lines use spaces, the fourth uses a tab. Broken on purpose:
def sale_price(price):
if price > 1000:
return price * 0.9
return price
print(sale_price(1500))
File "C:\projects\sale.py", line 4
return price
TabError: inconsistent use of tabs and spaces in indentation
The line number is exact. What appears under it depends on the version: the output above is Python 3.12, which prints nothing else, while Python 3.13 and newer add a lone ^ at the very start of the indent. Neither tells you much — there is nothing meaningful to point at, because the culprit is an invisible character.
Why does the code look perfectly aligned but Python still complains?
Because a tab is not "a character N columns wide" — it means "jump to the next tab stop". If your editor's tab size is 4, a tab takes exactly as much room as four spaces and the line sits in the same column as its neighbours. Your eyes see nothing; the interpreter sees two different indents. That is why staring at the file never finds this bug.
expandtabs() shows what a tab becomes at tab size 4:
print(repr(" return price".expandtabs(4)))
print(repr(" return price".expandtabs(4)))
print(repr(" return price".expandtabs(4)))
' return price'
' return price'
' return price'
The third line is the nasty one: four spaces plus a tab produce eight columns, exactly what two tabs produce. A line that looks "slightly more indented" is two levels deep.
How do you see the tabs without changing any settings?
Use repr(). It prints a tab as \t and leaves spaces as spaces, so one call tells you what a line is really made of:
print(repr(" return price"))
print(repr(" return price"))
' return price'
'\treturn price'
Run that check over every line of the file and you have a detector for the suspect line numbers.
How do I show whitespace in VS Code and PyCharm?
This is the step that turns an invisible problem into a visible one: the editor draws spaces as grey dots and tabs as arrows, so a tab-indented line stands out at a glance. One menu item, no plugins, no restart.
VS Code
View → Appearance → Render Whitespace, or the setting directly:
"editor.renderWhitespace": "all"
Spaces become ·, tabs become →. The status bar at the bottom right reads Spaces: 4 or Tab Size: 4 — that is what the editor inserts right now.
PyCharm
View → Active Editor → Show Whitespaces. Show Indent Guides in the same menu helps too: the vertical lines reveal the line that broke out of its level.
How do I convert an entire file from tabs to spaces?
Not by hand. Both editors reindent a whole file with one command: every leading tab becomes the right number of spaces, block structure survives, code inside the lines is untouched. That is the cure, as opposed to patching the one line Python named.
| Tool |
What to run |
What changes |
| VS Code |
Ctrl+Shift+P → Convert Indentation to Spaces |
Every leading tab becomes spaces |
| PyCharm |
Edit → Convert Indents → To Spaces |
Same, for a file or a folder |
| macOS, Linux |
expand -t 4 sale.py > fixed.py |
Expands all tabs, not just leading ones |
| Any OS |
black sale.py |
Indent becomes 4 spaces — but only if the file parses |
One caveat about expand: it expands every tab, including a real tab inside a string literal such as print("name value"), which changes your data. The editor commands and black touch indentation only.
And a caveat about black: it cannot format a file that already raises TabError — it stops with cannot use --safe with this file; failed to parse source file AST: inconsistent use of tabs and spaces in indentation. Run the editor command or expand first, then black. A file indented purely with tabs, with nothing mixed in, black converts to spaces without complaint.
What is the difference between TabError and IndentationError?
TabError is a subclass of IndentationError, which is a subclass of SyntaxError — issubclass(TabError, IndentationError) returns True. All three are raised while the file is parsed, before anything runs, but they mean different things: TabError means indentation is mixed, expected an indented block means it is missing where required, and unexpected indent means it appears where nothing opened a block.
All four messages verbatim, so you can match the one on your screen:
| Message |
What happened |
Fix |
TabError: inconsistent use of tabs and spaces in indentation |
One block mixes tabs and spaces |
Convert the file to spaces |
IndentationError: expected an indented block after 'if' statement on line 2 |
The body after a colon line was not indented |
Add 4 spaces to the body |
IndentationError: unexpected indent |
A line is indented, nothing opened a block |
Remove the indentation |
IndentationError: unindent does not match any outer indentation level |
A line left a block but matched no outer level |
Align with an outer block |
The second row, live — the if has no body:
price = 1500
if price > 1000:
print("discount")
File "C:\projects\discount.py", line 3
print("discount")
^^^^^
IndentationError: expected an indented block after 'if' statement on line 2
Since Python 3.10 the message finishes the thought: after 'if' statement on line 2 names the line whose body you forgot to indent. The handbook sections on if / elif / else and for and while loops list every statement that opens an indented block.
Where do the tabs come from in the first place?
The sources are mundane: copy-paste from a browser, code from GitHub written in a tab-configured editor, an editor that auto-detects indentation from the file you opened, and plain editors such as Notepad, where Tab inserts a literal tab.
The worst case is the file that does not crash. Below the first function uses spaces, the second a tab, and Python says nothing:
def sale_price(price):
return price * 0.9
def delivery_price(weight):
return 300
print(sale_price(1000), delivery_price(2))
900.0 300
Python only compares indentation inside a single block, and these are two blocks. The file works until you add a second, space-indented line to delivery_price. It then fails on that new line, which looks guilty even though the tab has been there all along.
How many spaces should a Python indent be?
Four. That is the direct recommendation in PEP 8, the official Python style guide: one nesting level equals four spaces. The interpreter accepts any consistent number of spaces, and even tabs, but four is what every linter expects and what you will read in everyone else's code. PEP 8 also states plainly that spaces are preferred and that the two must never be mixed.
Nested blocks are where this becomes muscle memory. FizzBuzz is a loop with an if / elif / else chain inside it: three indentation levels at once.
Editor settings that keep the error away
Three settings close the problem for good. In VS Code:
"editor.insertSpaces": true,
"editor.tabSize": 4,
"editor.detectIndentation": false
The third matters most. While detectIndentation is on, VS Code inspects the open file, finds a tab and inserts tabs even though you asked for spaces — that is how a clean project gets infected from one foreign file.
In PyCharm: Settings → Editor → Code Style → Python, clear Use tab character, set Tab size and Indent to 4, then clear Detect and use existing file indents for editing on the Code Style page.
An .editorconfig in the repository root applies the rule for everyone. PyCharm reads it out of the box; VS Code needs the EditorConfig extension:
root = true
[*.py]
indent_style = space
indent_size = 4
Checking from the terminal: tabnanny, not python -tt
The advice "run python -tt" survives on forums from the Python 2 era, where -t warned about ambiguous indentation and -tt made it an error. In Python 3 it does nothing: the option is accepted silently and is not listed in python --help. Ambiguous mixing is already a hard error. The working tool ships with the standard library:
$ python -m tabnanny sale.py
sale.py 4 '\treturn price'
Filename, line number, and the line through repr(), with the tab visible as \t. It walks directories too: python -m tabnanny .. Two caveats: it looks for ambiguity rather than tabs as such, so a tabs-only file passes silently, and its exit code is 0 even when it reports something. For CI use flake8 (rules W191 and E101) or black.
Common mistakes
- Fixing the indent with the Tab key. Pressing Tab adds one more tab — the same bug again. Type four spaces, or switch the editor to spaces first.
- Fixing only the line Python named. It reports the first line where indentation stopped adding up, not all of them. Fix one and the next fails. Reindent the whole file.
- Trusting your eyes. With whitespace rendering off, a tab and four spaces are indistinguishable, and no number of spaces reliably matches a tab.
- Assuming silence means correctness. Tabs and spaces in different blocks raise nothing today and TabError on your next edit.
- Reaching for
python -tt. In Python 3 it does nothing. Use tabnanny, flake8 or black.
- Not reading the message to the end.
expected an indented block after 'if' statement on line 2 names two lines: the failing one and the cause.
If the file crashes on a double-click and the console window vanishes before you can read the TabError, that is a separate problem, covered in why a Python script window closes instantly. Tabs are also not the only invisible characters that break a file — the other common case is encoding, covered in mojibake and UnicodeDecodeError when reading a file.
Practice: fix the indentation in the browser
Indentation sticks once your hands do it. Take Sum the even numbers: a loop with a condition inside it, two indentation levels — the exact shape where TabError strikes. Hidden tests grade it in the browser, no install required.
In short
TabError: inconsistent use of tabs and spaces in indentation means one block mixes tab and space indentation.
- It is invisible because a tab renders at the width of the neighbouring spaces. Turn on Render Whitespace (VS Code) or Show Whitespaces (PyCharm) first.
- The cure is one whole-file command —
Convert Indentation to Spaces or Edit → Convert Indents → To Spaces — not a patch to one line.
- To keep it away:
insertSpaces true, tabSize 4, detectIndentation false, plus an .editorconfig in the project root.
- TabError,
expected an indented block and unexpected indent are three different failures: mixed, missing, and extra indentation.
python -tt does nothing in Python 3; use python -m tabnanny file.py, flake8 or black. PEP 8: four spaces per level.
If Python reports
TabError: inconsistent use of tabs and spaces in indentation, one block of your code is indented with both tabs and spaces, and the interpreter cannot tell how deeply nested the line is. The fix is not rewriting code — it is two editor actions: turn on whitespace rendering, then convert the file to spaces (VS Code:Convert Indentation to Spaces; PyCharm: Edit → Convert Indents → To Spaces).Below: why the file looked aligned, how TabError differs from the two IndentationError messages people confuse it with, and which settings keep it away.
What does Python TabError inconsistent use of tabs and spaces mean?
TabError is Python refusing to guess. Indentation defines nesting, so the interpreter must know whether the current line is deeper than the previous one. If one line is indented with four spaces and the next with a tab, the answer depends on whether a tab counts as four columns or eight. Python will not pick for you — it stops before running a single statement.
A discount function: three lines use spaces, the fourth uses a tab. Broken on purpose:
def sale_price(price): if price > 1000: return price * 0.9 return price print(sale_price(1500))The line number is exact. What appears under it depends on the version: the output above is Python 3.12, which prints nothing else, while Python 3.13 and newer add a lone
^at the very start of the indent. Neither tells you much — there is nothing meaningful to point at, because the culprit is an invisible character.Why does the code look perfectly aligned but Python still complains?
Because a tab is not "a character N columns wide" — it means "jump to the next tab stop". If your editor's tab size is 4, a tab takes exactly as much room as four spaces and the line sits in the same column as its neighbours. Your eyes see nothing; the interpreter sees two different indents. That is why staring at the file never finds this bug.
expandtabs()shows what a tab becomes at tab size 4:print(repr(" return price".expandtabs(4))) print(repr(" return price".expandtabs(4))) print(repr(" return price".expandtabs(4)))The third line is the nasty one: four spaces plus a tab produce eight columns, exactly what two tabs produce. A line that looks "slightly more indented" is two levels deep.
How do you see the tabs without changing any settings?
Use
repr(). It prints a tab as\tand leaves spaces as spaces, so one call tells you what a line is really made of:print(repr(" return price")) print(repr(" return price"))Run that check over every line of the file and you have a detector for the suspect line numbers.
How do I show whitespace in VS Code and PyCharm?
This is the step that turns an invisible problem into a visible one: the editor draws spaces as grey dots and tabs as arrows, so a tab-indented line stands out at a glance. One menu item, no plugins, no restart.
VS Code
View → Appearance → Render Whitespace, or the setting directly:
Spaces become
·, tabs become→. The status bar at the bottom right readsSpaces: 4orTab Size: 4— that is what the editor inserts right now.PyCharm
View → Active Editor → Show Whitespaces. Show Indent Guides in the same menu helps too: the vertical lines reveal the line that broke out of its level.
How do I convert an entire file from tabs to spaces?
Not by hand. Both editors reindent a whole file with one command: every leading tab becomes the right number of spaces, block structure survives, code inside the lines is untouched. That is the cure, as opposed to patching the one line Python named.
Ctrl+Shift+P→Convert Indentation to Spacesexpand -t 4 sale.py > fixed.pyblack sale.pyOne caveat about
expand: it expands every tab, including a real tab inside a string literal such asprint("name value"), which changes your data. The editor commands andblacktouch indentation only.And a caveat about
black: it cannot format a file that already raises TabError — it stops withcannot use --safe with this file; failed to parse source file AST: inconsistent use of tabs and spaces in indentation. Run the editor command orexpandfirst, thenblack. A file indented purely with tabs, with nothing mixed in,blackconverts to spaces without complaint.What is the difference between TabError and IndentationError?
TabError is a subclass of IndentationError, which is a subclass of SyntaxError —
issubclass(TabError, IndentationError)returnsTrue. All three are raised while the file is parsed, before anything runs, but they mean different things: TabError means indentation is mixed,expected an indented blockmeans it is missing where required, andunexpected indentmeans it appears where nothing opened a block.All four messages verbatim, so you can match the one on your screen:
TabError: inconsistent use of tabs and spaces in indentationIndentationError: expected an indented block after 'if' statement on line 2IndentationError: unexpected indentIndentationError: unindent does not match any outer indentation levelThe second row, live — the
ifhas no body:price = 1500 if price > 1000: print("discount")Since Python 3.10 the message finishes the thought:
after 'if' statement on line 2names the line whose body you forgot to indent. The handbook sections on if / elif / else and for and while loops list every statement that opens an indented block.Where do the tabs come from in the first place?
The sources are mundane: copy-paste from a browser, code from GitHub written in a tab-configured editor, an editor that auto-detects indentation from the file you opened, and plain editors such as Notepad, where Tab inserts a literal tab.
The worst case is the file that does not crash. Below the first function uses spaces, the second a tab, and Python says nothing:
def sale_price(price): return price * 0.9 def delivery_price(weight): return 300 print(sale_price(1000), delivery_price(2))Python only compares indentation inside a single block, and these are two blocks. The file works until you add a second, space-indented line to
delivery_price. It then fails on that new line, which looks guilty even though the tab has been there all along.How many spaces should a Python indent be?
Four. That is the direct recommendation in PEP 8, the official Python style guide: one nesting level equals four spaces. The interpreter accepts any consistent number of spaces, and even tabs, but four is what every linter expects and what you will read in everyone else's code. PEP 8 also states plainly that spaces are preferred and that the two must never be mixed.
Nested blocks are where this becomes muscle memory. FizzBuzz is a loop with an
if/elif/elsechain inside it: three indentation levels at once.Editor settings that keep the error away
Three settings close the problem for good. In VS Code:
The third matters most. While
detectIndentationis on, VS Code inspects the open file, finds a tab and inserts tabs even though you asked for spaces — that is how a clean project gets infected from one foreign file.In PyCharm: Settings → Editor → Code Style → Python, clear Use tab character, set Tab size and Indent to 4, then clear Detect and use existing file indents for editing on the Code Style page.
An
.editorconfigin the repository root applies the rule for everyone. PyCharm reads it out of the box; VS Code needs the EditorConfig extension:Checking from the terminal: tabnanny, not python -tt
The advice "run
python -tt" survives on forums from the Python 2 era, where-twarned about ambiguous indentation and-ttmade it an error. In Python 3 it does nothing: the option is accepted silently and is not listed inpython --help. Ambiguous mixing is already a hard error. The working tool ships with the standard library:Filename, line number, and the line through
repr(), with the tab visible as\t. It walks directories too:python -m tabnanny .. Two caveats: it looks for ambiguity rather than tabs as such, so a tabs-only file passes silently, and its exit code is 0 even when it reports something. For CI use flake8 (rules W191 and E101) orblack.Common mistakes
python -tt. In Python 3 it does nothing. Usetabnanny, flake8 orblack.expected an indented block after 'if' statement on line 2names two lines: the failing one and the cause.If the file crashes on a double-click and the console window vanishes before you can read the TabError, that is a separate problem, covered in why a Python script window closes instantly. Tabs are also not the only invisible characters that break a file — the other common case is encoding, covered in mojibake and UnicodeDecodeError when reading a file.
Practice: fix the indentation in the browser
Indentation sticks once your hands do it. Take Sum the even numbers: a loop with a condition inside it, two indentation levels — the exact shape where TabError strikes. Hidden tests grade it in the browser, no install required.
In short
TabError: inconsistent use of tabs and spaces in indentationmeans one block mixes tab and space indentation.Convert Indentation to Spacesor Edit → Convert Indents → To Spaces — not a patch to one line.insertSpacestrue,tabSize4,detectIndentationfalse, plus an.editorconfigin the project root.expected an indented blockandunexpected indentare three different failures: mixed, missing, and extra indentation.python -ttdoes nothing in Python 3; usepython -m tabnanny file.py, flake8 orblack. PEP 8: four spaces per level.