← Back to PyDebug

Common Python Errors β€” Exact Messages, Causes & Fixes

Every Python error tells you three things: what went wrong (the error type), where (file and line number), and why (the message after the colon). This guide lists the errors beginners hit most often, each with the exact message, the common causes, a code example that triggers it, and the fix.

SyntaxError

Exact message: SyntaxError: invalid syntax β€” also SyntaxError: expected ':'

Fix in one line: Python could not parse your code β€” usually a missing :, a stray = where == belongs, or an unclosed bracket/string.

Common causes

  • A missing colon at the end of an if, for, while, or def line.
  • Using = (assignment) instead of == (comparison) in a condition.
  • An unclosed quote, bracket, or parenthesis that swallows the rest of the file.

Code that triggers it

if x == 5   # missing colon
    print(x)

How to fix it

Add the missing colon, swap = for ==, and let your editor highlight matching brackets. Read the caret (^) in the traceback β€” it points at the exact token Python choked on. Practice: missing colon after a function definition.

IndentationError

Exact message: IndentationError: expected an indented block β€” also IndentationError: unexpected indent

Fix in one line: Indent every block with exactly four spaces, consistently.

Common causes

  • A line after if/for/def that is not indented at all.
  • Mixing tabs and spaces so two lines look aligned but are not.
  • Copy-pasting code whose leading whitespace no longer lines up.

Code that triggers it

if True:
print("indented?")   # must be indented

How to fix it

Indent the block body by four spaces, and never mix tabs with spaces β€” configure your editor to insert spaces for tabs. Practice: missing indentation after if.

NameError

Exact message: NameError: name 'x' is not defined

Fix in one line: Define the variable (or function) before you use it, and check the spelling.

Common causes

  • Using a variable before assigning it.
  • Calling a function before its def line runs.
  • A typo in the name, or forgetting quotes so hello is read as a variable instead of the string "hello".

Code that triggers it

print(age)   # age never assigned

How to fix it

Move the assignment or def above the line that uses it, and double-check the spelling. Practice: using a variable before it's defined.

TypeError

Exact message: TypeError: can only concatenate str (not "int") to str β€” many variants exist

Fix in one line: Convert the values to a common type before combining them.

Common causes

  • Adding a string and a number with +.
  • Calling a non-function value like my_list() or len()().
  • Iterating over a non-iterable such as an int.

Code that triggers it

"The answer is " + 42   # can't add str and int

How to fix it

Convert explicitly β€” "The answer is " + str(42) or f"The answer is {42}" β€” and check the type of every value in the expression. Practice: mixing text and numbers in print.

IndexError

Exact message: IndexError: list index out of range

Fix in one line: Only index positions that exist β€” 0 to len(list)-1, or use -1 for the last item.

Common causes

  • Using list[3] on a 3-item list (valid indexes are 0, 1, 2).
  • A loop with range(len(list)) that runs one step too far.
  • Assuming a string index exists after a failed search or an empty list.

Code that triggers it

nums = [1, 2, 3]
print(nums[3])   # valid indexes: 0,1,2

How to fix it

Check len(nums) before indexing, use nums[-1] for the last element, or iterate with for x in nums so you never touch an index. Practice: wrong index to get the last item.

KeyError

Exact message: KeyError: 'age'

Fix in one line: Use dict.get(key, default) instead of dict[key] when the key may be missing.

Common causes

  • Accessing a key that was never inserted.
  • A typo in the key name.
  • Deleting a key with del and then reading it again.

Code that triggers it

data = {"name": "Alice"}
print(data["age"])   # 'age' key doesn't exist

How to fix it

Prefer data.get("age") (returns None or a fallback), or test if "age" in data: first. Practice: accessing a missing dictionary key.

ValueError

Exact message: ValueError: invalid literal for int() with base 10: 'abc' β€” also ValueError: too many values to unpack

Fix in one line: Validate (or catch) the bad value before the conversion, and match the number of unpacked values.

Common causes

  • Calling int() on text that is not a number.
  • Unpacking a sequence into too few or too many variables.
  • Passing an out-of-range value to a function like math.sqrt(-1).

Code that triggers it

int("hello")   # can't convert string to int

How to fix it

Wrap the conversion in try/except ValueError, or validate the input first. Practice: converting text that isn't a number.

AttributeError

Exact message: AttributeError: 'str' object has no attribute 'append'

Fix in one line: Check type(value) where the error occurs and use a method that type actually has.

Common causes

  • Calling a list method on a string (or vice versa).
  • A typo in the method name, like trim() instead of strip().
  • A function returned None and you chained a call on it.

Code that triggers it

numbers = "1,2,3"      # a string, not a list!
numbers.append(4)       # 'str' object has no attribute 'append'

How to fix it

Print type(numbers) just above the crash β€” method-name surprises usually mean the value is not the type you assumed. Practice: wrong method to remove whitespace.

ZeroDivisionError

Exact message: ZeroDivisionError: division by zero

Fix in one line: Guard the zero/empty case before dividing.

Common causes

  • Averaging an empty list: sum([]) / len([]).
  • Dividing by a counter that starts at zero and is never incremented.
  • Taking modulo by zero.

Code that triggers it

average = total / count   # crashes when count is 0

How to fix it

Handle the empty case explicitly: average = total / count if count else 0. Practice: dividing without checking for zero.

UnboundLocalError

Exact message: UnboundLocalError: local variable 'count' referenced before assignment

Fix in one line: Pass the value in and return the new one β€” or declare it global.

Common causes

  • Reading a variable in a function that is assigned later in the same function.
  • Incrementing a global counter without global.
  • Shadowing a global name with a local assignment on a later line.

Code that triggers it

count = 0
def bump():
    count = count + 1   # count is local here, read before assignment
    return count

How to fix it

Best practice: def bump(count): return count + 1. If you must mutate a global, add global count as the first line. Practice: modifying a variable before it's assigned locally.

RecursionError

Exact message: RecursionError: maximum recursion depth exceeded

Fix in one line: Give the recursive function a base case that actually triggers.

Common causes

  • A missing or unreachable base case.
  • The recursive argument never converges (e.g. countdown(n-2) skipping past 0).
  • A wrong condition that makes the base case compare the wrong value.

Code that triggers it

def countdown(n):
    print(n)
    countdown(n - 1)   # missing: if n <= 0: return

How to fix it

Write the base case first, then the recursive step, and verify the argument moves toward the base case every call.

RuntimeError

Exact message: RuntimeError: dictionary changed size during iteration

Fix in one line: Never add or remove dict keys while iterating over that same dict.

Common causes

  • Deleting keys inside a for key in d: loop.
  • Adding keys while looping over d.items().
  • Calling a helper that mutates the dict mid-loop.

Code that triggers it

for key in prices:
    if prices[key] == 0:
        del prices[key]   # RuntimeError

How to fix it

Iterate over a copy β€” for key in list(prices): β€” or build a new dict with a comprehension. Practice: modifying a dict while looping over it.

ImportError / ModuleNotFoundError

Exact message: ModuleNotFoundError: No module named 'pandas'

Fix in one line: Check the spelling, install the package, and don't name your file after a stdlib module.

Common causes

  • The package is not installed.
  • A typo in the module name.
  • A local file (like random.py) shadowing a standard-library module.

Code that triggers it

import matplotib.pyplot   # typo β€” ModuleNotFoundError

How to fix it

Fix the spelling, run pip install, and rename any file that collides with a stdlib name.

StopIteration

Exact message: StopIteration β€” raised when next() runs past the end of an iterator

Fix in one line: Catch it, or pass a default to next().

Common causes

  • Calling next() one time too many.
  • Reusing an exhausted generator after it has already been fully consumed.
  • A while loop with no stop condition on an iterator.

Code that triggers it

nums = iter([10, 20])
print(next(nums)); print(next(nums)); print(next(nums))   # StopIteration

How to fix it

Use next(nums, default) to return a fallback at the end, or wrap the loop in try/except StopIteration.

πŸ”¬ How to Read a Traceback, Top to Bottom

A traceback looks scary but is a fixed-shape story with three parts:

Traceback (most recent call last):
  File "app.py", line 12, in <module>      ← 1. the chain of calls, newest last
  File "app.py", line 7, in compute_total
    return total / count
ZeroDivisionError: float division by zero  ← 2. the real message
                                           ← 3. read from the BOTTOM up

Work backwards: read the final line first (the error type and message), then the last frame above it (the exact file and line that crashed), then walk upward until you reach your code. In beginner programs, the top-most non-library frame is almost always where the wrong value was born one or two lines earlier.

🌳 The Family Tree Behind the Names

Every exception above inherits from a small hierarchy rooted at BaseException. LookupError families (IndexError, KeyError) mean "you asked for something not there"; ArithmeticError families (ZeroDivisionError) mean "the maths was illegal"; NameError and AttributeError mean "this name doesn't exist here"; and TypeError/ValueError distinguish "wrong kind of thing" from "right kind, wrong value". Reading an error name as a branch of this tree finishes half the diagnosis before you read the message.

πŸ›‘οΈ Preventing Tomorrow's Errors Today

Three habits remove most of the errors above before they happen: convert input at the boundary β€” int(value) once, inside try/except ValueError, where the string enters your program. Validate emptiness at the start of any function that divides, indexes, or averages. And name things out loud β€” the two errors beginners most regret (UnboundLocalError and the stdlib-shadowing ImportError) are both naming problems.

πŸ’ͺ Building Error Fluency on Purpose

The shortcut to fluency is to trigger errors deliberately: in the Playground, spend five minutes causing each error above β€” index past the end, divide by zero, mix tabs and spaces. Once you have made an error on purpose, you read it as a known visitor with a known cause, not a wall of red. PyDebug's fix-the-bug problems are built from exactly this idea β€” every problem is one of these error patterns wearing camouflage.

πŸ”— Keep Going

  • Fix‑the‑Bug problems β€” practice every error above on real broken snippets.
  • Python debugging guide β€” a systematic step-by-step method.
  • 15 Common Python Errors Guide β€” deeper root-cause walkthroughs.
  • Output prediction tricks β€” 10 tricky interview questions explained.
  • Python glossary β€” every term used on this page, defined.