IndentationError

In Python the indentation is the block structure, so a wrong indent is a syntax error — raised at compile time, with TabError as the special case for tabs and spaces that only line up at some tab widths.

InheritsBaseException›Exception›SyntaxError›IndentationError
Import / syntax exceptionPython 3 (all)Live demo
IndentationError(messagemessage — The error text (e.msg).type: str · default: null, detailsdetails — Same as SyntaxError: (filename, lineno, offset, text[, end_lineno, end_offset]).type: tuple · default: null)
Raised by
compiling a file, exec(), compile() — never while code runs
Message
expected an indented block after … · unexpected indent · unindent does not match any outer indentation level
Quick fix
indent with 4 spaces everywhere; an empty body needs pass
Watch out
TabError: a tab and 8 spaces look identical but are rejected

Demo

Live evaluation
A three-line loop. Choose how many spaces indent line 2 and line 3 — the numbers decide whether line 3 is inside the loop, after it, or an error.
Try:
Inputs
firstintspaces before line 2
secondintspaces before line 3
Code
src = 'for i in range(3):\n' + ' ' * 4 + 'n += 1\n' + ' ' * 4 + 'n += 10\n'
n = 0
exec(src)
n
Result
33

In Trigger, 4 / 4 gives 33 (line 3 runs three times inside the loop) and 4 / 0 gives 13 (once, after it) — same code, different meaning. 4 / 2 dedents to a column no enclosing block uses. In Handle, a tab and 8 spaces reach the same column, yet Python raises TabError: it also measures every line with a tab counted as 1 column, and the two measurements must agree about which lines line up.

Constructor

NameTypeRequiredDescription
messagestrnoThe error text (e.msg).
detailstuplenoSame as SyntaxError: (filename, lineno, offset, text[, end_lineno, end_offset]).

Attributes

AttributeTypeMeaning
msgstrThe message, e.g. "expected an indented block after 'if' statement on line 1" — note it names the statement and line that needed the block.
linenoint | NoneThe line with the bad indentation (for a missing block, the line that should have been indented).
textstr | NoneThat source line.
offset / filename / end_lineno / end_offsetint | str | NoneInherited from SyntaxError.

Common patterns

An empty block needs a statement
pass, ... or a docstring all count as a body. A comment does not.
def not_ready_yet():
    pass

class Placeholder:
    """Filled in later."""
Dedent code stored in strings
Source kept in an indented triple-quoted string starts with spaces — dedent it before compile()/exec().
import textwrap
snippet = '''
    def f():
        return 1
'''
exec(textwrap.dedent(snippet))
Normalize tabs in legacy files
Convert tabs to spaces once (editor "convert indentation", or expandtabs), then keep a single style.
with open('legacy.py', encoding='utf-8') as f:
    fixed = f.read().expandtabs(4)

Examples

1. Block without a body
src = 'if ok:\nreturn 1' try: compile(src, 'app.py', 'exec') except IndentationError as e: r = (e.msg, e.lineno, e.text) r
Returns
("expected an indented block after 'if' statement on line 1", 2, 'return 1\n')
2. One space too many
src = 'def f():\n x = 1\n return x' compile(src, 'app.py', 'exec')
Returns
IndentationError: unexpected indent
3. Dedent to a level that never existed
src = 'def f():\n if x:\n pass\n return x' compile(src, 'app.py', 'exec')
Returns
IndentationError: unindent does not match any outer indentation level
4. TabError: 4 spaces then a tab
src = 'def f():\n x = 1\n\treturn x' compile(src, 'app.py', 'exec')
Returns
TabError: inconsistent use of tabs and spaces in indentation
5. Tabs only are fine
src = 'def f():\n\tx = 1\n\treturn x' compile(src, 'app.py', 'exec') is not None
Returns
True
6. TabError is an IndentationError is a SyntaxError
try: compile('if x:\n a = 1\n\tb = 2', 'app.py', 'exec') except SyntaxError as e: r = type(e).__mro__[:3] [c.__name__ for c in r]
Returns
['TabError', 'IndentationError', 'SyntaxError']
7. Leading spaces in exec()
exec(' x = 1')
Returns
IndentationError: unexpected indent

Pitfalls

1. A comment is not a block body
Comments are dropped by the tokenizer, so a block containing only a comment is empty.
Comment only
src = 'def todo():\n    # later\n'
compile(src, 'app.py', 'exec')
IndentationError: expected an indented block after function definition on line 1
Add pass
src = 'def todo():\n    # later\n    pass\n'
compile(src, 'app.py', 'exec') is not None
True
2. Indented code in a triple-quoted string
The string keeps the indentation of the surrounding source, so its first statement is "unexpectedly" indented.
As written
code = '''
    def f():
        return 1
'''
compile(code, 'app.py', 'exec')
IndentationError: unexpected indent
textwrap.dedent
import textwrap
code = '''
    def f():
        return 1
'''
compile(textwrap.dedent(code), 'app.py', 'exec') is not None
True
3. Pasted code that mixes tabs and spaces
Lines that look aligned in the editor can be a tab on one line and spaces on the next. Convert the file to spaces instead of adjusting single lines.
Mixed
src = 'def f():\n    x = 1\n\treturn x'
compile(src, 'app.py', 'exec')
TabError: inconsistent use of tabs and spaces in indentation
expandtabs(4)
src = 'def f():\n    x = 1\n\treturn x'
compile(src.expandtabs(4), 'app.py', 'exec') is not None
True

When to use

Use it
  • Catching it (or SyntaxError) around compile()/exec() of generated or user-supplied code
  • Raising it from a tool that parses an indentation-based format
Reach for something else
  • Catching it in your own module → it is compiled before any try runs; fix the file
  • Fixing TabError line by line → convert the whole file to spaces

Notes

CPython impl
Parser/lexer/lexer.c — each line gets col (tab = next multiple of 8) and altcol (tab = 1); if the two disagree about indent/dedent/same level, TabError. "unexpected indent" and "expected an indented block" come from the parser
Catch via
except SyntaxError catches IndentationError and TabError
TabError
Subclass of IndentationError: "inconsistent use of tabs and spaces in indentation"
PEP8
4 spaces per level; never mix tabs and spaces

FAQ

The line after a statement ending in a colon (if, for, while, def, class, with, try, except, match …) must be indented deeper. The message names that statement and its line number. If the block is intentionally empty, write pass (or ...) — a comment alone is not a body.