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 indentation

All 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, or try with 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

  1. Open the file.
  2. Look at the bottom-right status bar. It says either Spaces: 4 or Tab Size: 4.
  3. Click it and select Indent Using Spaces, then choose 4.
  4. Open the Command Palette (Ctrl+Shift+P / Cmd+Shift+P).
  5. 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

  1. Go to SettingsEditorCode StylePython.
  2. Under the Tabs and Indents tab, uncheck Use tab character.
  3. Set Tab size, Indent, and Continuation indent to 4.
  4. To fix an existing file: CodeReformat Code (Ctrl+Alt+L / Cmd+Alt+L).

Sublime Text

  1. Go to ViewIndentation.
  2. Uncheck Indent Using Tabs.
  3. Set Tab Width to 4.
  4. Select all (Ctrl+A / Cmd+A), then ViewIndentationConvert Indentation to Spaces.

Vim / Neovim

Add to your config:

set expandtab
set tabstop=4
set shiftwidth=4
set softtabstop=4

To convert tabs to spaces in an open file:

:set expandtab
:retab

Fix 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.py

black 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.py

autopep8 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.py

ruff 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 later

Every block after a colon needs at least one statement. Use pass as a placeholder:

def placeholder():
    pass

class MyModel:
    pass

if condition:
    pass

You 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.py

This 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.py

Tabs 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 ViewRender 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:

  1. Select all the pasted lines.
  2. Remove all leading whitespace (Shift+Tab repeatedly, or dedent to column 0).
  3. 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.py

To replace them:

sed -i 's/\xc2\xa0/ /g' app.py

Or 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 fine

The 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 indent

The 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 = true

Most 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.py

Or 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-diff

Or view whitespace changes explicitly:

git diff --ws-error-highlight=all

Pre-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 install

Now 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