IndentationError: expected an indented block
1 · The lesson
readWhat this error means
Python opened a block with : (after if, for, def, class, while, try, else, with, etc.) but found no indented lines underneath it. Every colon-terminated header needs at least one statement in its body — Python does not allow empty blocks the way some languages do with {}.
When you see it
>>> def greet(name): ... File "<stdin>", line 2 ^ IndentationError: expected an indented block after function definition on line 1
>>> if x > 0: ... print(x) File "<stdin>", line 2 print(x) ^ IndentationError: expected an indented block after 'if' statement on line 1
Why it happens
You wrote a header line and then either left it empty, forgot to indent the body, or deleted the body while refactoring and forgot to add a placeholder. It also happens when copy-pasting code where the indentation was stripped or replaced by something Python doesn't recognise.
How to fix it
1. Add a real body:
def greet(name): print("Hello,", name)
2. Use pass as a no-op placeholder:
def todo(): pass if x > 0: pass # implement later
setup added so this can run · defines x
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) x = _AutoMock('x')
pass is a literal "do nothing" statement, perfect for stubbing out code you'll fill in.
3. Use a docstring — a string on its own line counts as a statement:
def greet(name): """Greet the user by name. Implementation pending."""
This is common in abstract methods, scaffolding, and placeholder classes:
class UserRepository: """Stores and retrieves users.""" def find(self, user_id): """Return the user with the given id, or None."""
4. Use ... (Ellipsis) — a single dot-dot-dot is also a valid statement:
def not_yet_implemented(): ...
This is idiomatic in type stubs and abstract method bodies.
When you'd actually see this in real code
- Sketching out a class with several methods you plan to fill in later — every method needs
pass,..., or a docstring. - Commenting out the only line inside an
ifblock while debugging — the block becomes empty. Comments are not statements; you still needpass. - Pasting code into a notebook or REPL where the indented lines didn't make it across.
Related errors
See Also
- All Python errors — the full index, by type and by when it happens.
- Python syntax cheat sheet
- Functions tutorial