The 20 Python Errors Beginners Hit First (and How to Fix Each)
The traceback's last line names the error; the line above it in YOUR file is where to look. Start there, not at the top of the output.
Syntax and Structure
1. IndentationError: unexpected indent — a line is indented more than its block needs (often pasted code with mixed tabs/spaces). Fix: re-indent the block; configure your editor to insert 4 spaces. See the IndentationError guide.
2. SyntaxError: invalid syntax — the parser stopped where code stopped making sense. Look at the marked position AND the end of the previous line: a missing :, an unclosed bracket, or using = instead of == in a condition. if x = 5: is the classic.
3. SyntaxError: EOL while scanning string literal — unclosed quote on that line. Multi-line strings need triple quotes.
Names and Scope
4. NameError: name 'x' is not defined — using a variable before defining it, or a typo (prnit), or reading a global without declaring it. Check the spelling first; it's usually the spelling.
5. UnboundLocalError: local variable referenced before assignment — the confusing one: inside a function, assigning to a name makes it local everywhere in that function, so reading it before the assignment fails even if a global exists. Fix: pass it as a parameter, or declare global x / nonlocal x (and consider whether the design wants that).
6. ModuleNotFoundError: No module named 'x' — the package isn't installed, or you're in the wrong virtualenv, or the module name differs from the install name (PIL vs Pillow, cv2 vs opencv-python). Check with pip list. Full guide.
7. ImportError: cannot import name 'x' from 'y' — the name doesn't exist in that module (wrong version, or it moved). Different from 6: the module was found, the name wasn't. Also a classic circular-import symptom — two modules importing each other.
Types and Values
8. TypeError: can only concatenate str (not "int") to str — "Age: " + 25. Fix: f"Age: {25}" (preferred) or str(25).
9. TypeError: 'NoneType' object is not subscriptable — indexing something a function returned as None (functions without a return statement return None). Check what you assigned: x = print(...) is the beginner version; x = dict.get('missing') without a default is the experienced one.
10. TypeError: unsupported operand type(s) — arithmetic across incompatible types, e.g. "5" * "3". Convert with int()/float() — and note "5" * 3 is legal (string repetition) while "5" - 1 is not.
11. TypeError: 'list' object is not callable — you named a variable the same as a builtin/function: list = [1,2]; list(). Rename (items, numbers) — never shadow list, dict, str, id, type.
12. ValueError: invalid literal for int() with base 10: 'abc' — converting a non-numeric string. Validate first, or catch it: try: n = int(s) except ValueError: n = 0.
13. ValueError: too many values to unpack — a, b = [1, 2, 3]. Match the count, or use the star: a, *rest = items.
14. ZeroDivisionError — dividing by zero, including x % 0. Guard the denominator; if the zero is legitimate data, return a sentinel instead of crashing.
Collections
15. IndexError: list index out of range — index beyond the end (including index 0 on an empty list). Remember Python indexes are 0-based: a 3-item list has indexes 0,1,2. Check len() or iterate directly.
16. KeyError: 'x' — missing dict key. d.get('x', default) or if 'x' in d. Full guide.
17. AttributeError: 'NoneType' object has no attribute 'x' — calling a method on None: result = find(); result.upper() where find() found nothing. Check for None: if result: or use the walrus for both: if (m := re.search(...)):. Full guide.
The Async and Runtime Ones
18. RuntimeError: dictionary changed size during iteration — adding/removing keys while looping over a dict. Iterate over a copy: for k in list(d):, or build a new dict.
19. RecursionError: maximum recursion depth exceeded — missing base case, or a genuinely deep recursion. Add the base case first; if the depth is legitimate, rewrite iteratively.
20. RuntimeError: Event loop is closed — asyncio code calling async operations after the loop shut down or across loops (common with asyncio.run() called twice, or mixing sync libraries). Keep one loop; do not call asyncio.run inside a running loop — use await.
The Two Habits That Prevent Half of These
- Read the last two lines of the traceback first — the error, then the line in your file. Beginners read top-down and get lost in framework frames.
- Print the type when confused:
print(type(x), repr(x))answers "why is this behaving weirdly" in one second — the answer is almost always None, a string that looks like a number, or a list where you expected an element.