Fix: IndentationError: unexpected indent (Python)
The Error
You run a Python script and get one of these:
File "app.py", line 4
print("hello")
^
IndentationError: unexpected indent File "app.py", line 3
print("hello")
^
IndentationError: expected an indented block File "app.py", line 4
print("hello")
^
TabError: inconsistent use of tabs and spaces in indentationAll three are indentation errors. Python uses indentation to define code blocks (where other languages use braces {}). When the indentation is wrong, Python refuses to run your code.
Why This Happens
Python is strict about indentation. Every block of code after a colon (:) must be indented, and every line in the same block must be indented by the same amount using the same character (tabs or spaces).
The most common causes:
- Mixing tabs and spaces. Your file uses tabs on some lines and spaces on others. They may look identical in your editor, but Python sees them as different characters.
- Copy-pasting code. You copied code from a website, Stack Overflow, or another file. The pasted code brought in different indentation characters or levels.
- Empty block after a colon. You wrote
if,for,def,class, ortrywith a colon but left the body empty. Python expects at least one indented line. - Extra indentation. A line is indented more than it should be, outside of any block.
- Editor mixing indentation styles. Your editor inserts tabs, but the rest of the file uses spaces (or vice versa).
Fix 1: Convert All Indentation to Spaces
The Python community standard is 4 spaces per indent level (PEP 8). Tabs are technically allowed, but mixing tabs and spaces is not. The simplest fix is to convert everything to spaces.
VS Code
- Open the file.
- Look at the bottom-right status bar. It says either
Spaces: 4orTab Size: 4. - Click it and select Indent Using Spaces, then choose 4.
- Open the Command Palette (
Ctrl+Shift+P/Cmd+Shift+P). - Search for Convert Indentation to Spaces and run it.
To make this the default for all Python files, add to your settings.json:
{
"[python]": {
"editor.insertSpaces": true,
"editor.tabSize": 4,
"editor.detectIndentation": false
}
}Note: Setting editor.detectIndentation to false prevents VS Code from auto-detecting and matching a file’s existing (possibly broken) indentation style.
PyCharm
- Go to Settings → Editor → Code Style → Python.
- Under the Tabs and Indents tab, uncheck Use tab character.
- Set Tab size, Indent, and Continuation indent to
4. - To fix an existing file: Code → Reformat Code (
Ctrl+Alt+L/Cmd+Alt+L).
Sublime Text
- Go to View → Indentation.
- Uncheck Indent Using Tabs.
- Set Tab Width to 4.
- Select all (
Ctrl+A/Cmd+A), then View → Indentation → Convert Indentation to Spaces.
Vim / Neovim
Add to your config:
set expandtab
set tabstop=4
set shiftwidth=4
set softtabstop=4To convert tabs to spaces in an open file:
:set expandtab
:retabFix 2: Use a Formatter (autopep8 or black)
Auto-formatters fix indentation issues instantly. Run one on your file and the problem goes away.
black
pip install black
black app.pyblack reformats the entire file to a consistent style, including indentation. It is opinionated and doesn’t offer many configuration options—that’s the point.
autopep8
pip install autopep8
autopep8 --in-place app.pyautopep8 fixes PEP 8 violations, including indentation. It’s less aggressive than black and preserves more of your original formatting.
ruff
pip install ruff
ruff format app.pyruff is a fast Python linter and formatter written in Rust. Its formatter is compatible with black’s style.
Note: Formatters fix whitespace issues, but they can’t fix logical indentation errors. If your code is indented at the wrong level (e.g., a return statement outside its function), you need to fix that manually.
Fix 3: Add pass to Empty Blocks
If you wrote a function, class, loop, or conditional with an empty body, Python raises IndentationError: expected an indented block:
def placeholder():
# nothing here yet
class MyModel:
# TODO: implement this
if condition:
# will fill in laterEvery block after a colon needs at least one statement. Use pass as a placeholder:
def placeholder():
pass
class MyModel:
pass
if condition:
passYou can also use ... (Ellipsis) for stubs, which is common in type stubs and abstract methods:
def not_implemented_yet():
...Fix 4: Detect Tabs vs Spaces with python -tt
Python 3 raises TabError when it detects mixed tabs and spaces in the same file. But some mixed-indentation issues slip through if tabs and spaces are used on different logical blocks.
Run your script with the -tt flag to force Python to treat all tab/space inconsistencies as errors:
python -tt app.pyThis turns warnings into hard errors, making it easier to find the problem lines.
Inspect whitespace characters
You can also check your file for invisible characters from the command line.
Linux/macOS:
cat -A app.pyTabs appear as ^I. Spaces appear as regular spaces. If you see lines starting with ^I and others starting with spaces, that’s your problem.
Windows (PowerShell):
Get-Content app.py | ForEach-Object { $_ -replace "`t", "→" }VS Code: Toggle View → Render Whitespace (or set "editor.renderWhitespace": "all" in settings). Tabs appear as arrows, spaces as dots.
Fix 5: Fix Copy-Paste Indentation
Code copied from websites, PDFs, or emails often brings in broken indentation. The pasted code may use different-width spaces, tabs, non-breaking spaces (\xa0), or a mix.
After pasting code:
- Select all the pasted lines.
- Remove all leading whitespace (Shift+Tab repeatedly, or dedent to column 0).
- Re-indent from scratch using your editor’s indent command (Tab).
Non-breaking spaces
Some websites and chat apps use non-breaking spaces (Unicode \xa0, ) instead of regular spaces. Python doesn’t recognize these as indentation. They’re invisible in most editors.
To find them:
grep -P "\xc2\xa0" app.pyTo replace them:
sed -i 's/\xc2\xa0/ /g' app.pyOr in Python:
with open("app.py", "r") as f:
content = f.read()
content = content.replace("\xa0", " ")
with open("app.py", "w") as f:
f.write(content)Fix 6: Fix Multiline String Indentation
Multiline strings (triple-quoted) can cause IndentationError: unexpected indent if you’re not careful with the surrounding code:
def greet():
message = """
Hello,
World!
"""
print(message) # This is fineThe problem happens when indentation inside the string is confused with code indentation. This is valid Python—the content inside triple quotes is just a string, not code. But if you break out of the string with wrong indentation:
def greet():
message = """
Hello,
World!
"""
print(message) # IndentationError: unexpected indentThe print line is over-indented. It should be at the same level as message.
If you want the string content to have no leading whitespace, use textwrap.dedent:
import textwrap
def greet():
message = textwrap.dedent("""\
Hello,
World!
""")
print(message)Fix 7: Set Up .editorconfig
An .editorconfig file ensures consistent indentation across editors and team members. Create a .editorconfig file in your project root:
root = true
[*.py]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = trueMost editors (VS Code, PyCharm, Sublime Text, Vim) respect .editorconfig natively or with a plugin. This prevents indentation mismatches when multiple people work on the same codebase.
Fix 8: Use expandtabs() for Runtime Tab Handling
If you’re reading code or text from an external source at runtime and need to normalize tabs to spaces, use Python’s built-in str.expandtabs():
line = "\t\tprint('hello')"
normalized = line.expandtabs(4)
print(repr(normalized))
# ' print(\'hello\')'This replaces each tab with spaces up to the next multiple of the tab size. Useful when processing code from files or user input.
Still Not Working?
Check for mixed encoding
If your file was edited on different operating systems or with different editors, it might have mixed line endings (\r\n vs \n). While this usually doesn’t cause indentation errors, some edge cases involving \r (carriage return) in the middle of lines can confuse Python’s parser.
Fix line endings:
# Convert to Unix line endings (LF)
sed -i 's/\r$//' app.pyOr in VS Code, click CRLF or LF in the bottom-right status bar and switch to LF.
Indentation error inside eval() or exec()
If you’re building Python code as a string and running it with exec() or eval(), indentation inside the string must be correct:
# Wrong — the 'return' line has extra indentation relative to 'def'
code = """
def add(a, b):
return a + b
"""
exec(code) # IndentationError
# Correct
code = """
def add(a, b):
return a + b
"""
exec(code)When using exec() with dynamically generated code, use textwrap.dedent() to strip common leading whitespace:
import textwrap
code = textwrap.dedent("""
def add(a, b):
return a + b
""")
exec(code)Jupyter Notebooks
Jupyter cells are independent, but indentation within a cell must still be consistent. A common issue: you copy code from a .py file into a notebook cell and the first line has extra indentation because it was inside a function in the original file.
Select all code in the cell and dedent it to start at column 0, then re-indent as needed.
Git diff shows no visible change but indentation is different
If git diff shows a line as changed but you can’t see the difference, it’s almost certainly a tab-vs-space change. Run:
git diff --word-diffOr view whitespace changes explicitly:
git diff --ws-error-highlight=allPre-commit hooks to prevent future issues
Add a pre-commit hook to catch indentation issues before they enter your codebase:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/psf/black
rev: 24.10.0
hooks:
- id: black
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: mixed-line-ending
args: ['--fix=lf']Install and run:
pip install pre-commit
pre-commit installNow every commit will be auto-formatted, and tab/space issues will be caught automatically.
Related: If you’re seeing import errors after fixing indentation, see Fix: ModuleNotFoundError: No module named. For pip install issues on modern Python, see Fix: error: externally-managed-environment.
Related Articles
Fix: Python IndentationError – Unexpected Indent or Expected an Indented Block
How to fix Python IndentationError including unexpected indent, expected an indented block, and unindent does not match, caused by mixed tabs and spaces or incorrect nesting.
Fix: pip No Matching Distribution Found for <package>
How to fix the pip error 'No matching distribution found' when installing Python packages, including version conflicts, platform issues, and index problems.
Fix: ImportError: cannot import name 'X' from partially initialized module (circular import)
How to fix Python's circular import error: ImportError cannot import name from partially initialized module. Covers lazy imports, module restructuring, TYPE_CHECKING, Django, Flask, and more.
Fix: django.db.utils.OperationalError: no such table (SQLite / PostgreSQL / MySQL)
How to fix Django's 'OperationalError: no such table' error caused by missing migrations, wrong database configuration, corrupted files, or Docker volume issues.