Menu
Try in Playground

Python Error Types and Debugging: Reading Tracebacks and Fixing Common Errors

A tour of the Python errors you'll meet most often — KeyError, ValueError, ModuleNotFoundError, EOFError — and the debugging habits that fix them quickly.

Errors Are How Python Tells You What Happened

Every Python error is an object with a type, a message, and a traceback — the chain of calls that led to it. Reading one well is the single biggest debugging skill you can pick up. This page is a tour of the errors you'll actually meet, and the habits that make fixing them fast.

For a deeper look at the mechanics of try/except and raising your own, the Exceptions page covers the syntax. This page is about the specific errors and how to read them.

Reading a Traceback

Run something that breaks:

def divide(a, b):
    return a / b

def report(values):
    for v in values:
        print(divide(10, v))

report([5, 2, 0])

Python prints something like:

Traceback (most recent call last):
  File "script.py", line 8, in <module>
    report([5, 2, 0])
  File "script.py", line 6, in report
    print(divide(10, v))
  File "script.py", line 2, in divide
    return a / b
ZeroDivisionError: division by zero

Read this bottom-up:

  1. ZeroDivisionError: division by zero — the exception type and message. This is what went wrong.
  2. return a / b at divide, line 2 — the line that actually raised.
  3. print(divide(10, v)) at report, line 6 — the call that triggered it.
  4. report([5, 2, 0]) at module level, line 8 — where it started.

The bottom frame is almost always where the fix goes. When a library throws an error deep in its internals, walk up the traceback to the first frame in your code — that's the call you passed bad input to.

The Errors You'll Meet Most Often

NameError

main.py
Output
Click Run to see the output here.

"Name 'mesage' is not defined." Caused by typos or using a variable before it's assigned. Python's error message usually names a likely replacement on recent versions ("Did you mean 'message'?").

Fix: check the spelling and scope. If the name only exists inside a function, you can't read it from outside.

TypeError

main.py
Output
Click Run to see the output here.

"Can only concatenate str (not 'int') to str." Wrong type for the operation. Classics: adding a string to a number, calling something that isn't callable, passing the wrong number of arguments to a function.

Fix: convert types explicitly (str(30), int("30")) or inspect what you're actually passing in. An f-string usually reads better than +-concatenation across types: f"age: {30}".

ValueError

main.py
Output
Click Run to see the output here.

"Invalid literal for int() with base 10: 'hello'." The type is right — int() accepts a string — but the value doesn't fit. Common with int(), float(), datetime parsing, and functions that take a bounded argument.

Fix: validate before converting, or catch the error and handle it:

main.py
Output
Click Run to see the output here.

KeyError

main.py
Output
Click Run to see the output here.

"KeyError: 'charlie'." The key isn't in the dict. Three idiomatic fixes, picked by intent:

main.py
Output
Click Run to see the output here.

For a dict where missing keys should auto-initialise, collections.defaultdict is worth a look.

IndexError

main.py
Output
Click Run to see the output here.

"List index out of range." You asked for a position the sequence doesn't have.

Fix: guard with a length check, use -1 to reference the last element, or use slicing (numbers[5:6] returns [] instead of raising).

AttributeError

main.py
Output
Click Run to see the output here.

"'NoneType' object has no attribute 'upper'." You called a method on something that doesn't have it. Almost always means a variable is an unexpected type — often None when you expected a real value.

Fix: figure out where the None came from. print(type(var)) or a breakpoint right before the error is the fastest way. Functions that "sometimes fail" usually return None; check their return value before calling methods on it.

ModuleNotFoundError (and ImportError)

import fastapi

"No module named 'fastapi'." The package isn't installed in the Python interpreter your script is using. Two common causes:

  1. You really haven't installed it. Run python -m pip install fastapi in the right environment.
  2. You installed it, but into a different Python. Happens constantly on macOS when pip and python point at different installs.

The reliable fix is to install with the same interpreter you run with:

python -m pip install fastapi

If you use a virtual environment (and you should), make sure it's activated before both pip install and python script.py.

FileNotFoundError

with open("settings.yaml") as f:
    config = f.read()

"[Errno 2] No such file or directory: 'settings.yaml'." The path doesn't exist relative to wherever the script is running.

Fix: print os.getcwd() at the top of the script to confirm where Python is looking. Use absolute paths or pathlib.Path(__file__).parent / "settings.yaml" to anchor paths to the script's own location.

EOFError

name = input("Name: ")

"EOF when reading a line." input() tried to read from stdin and got nothing — either the input was piped from an empty source, or you hit Ctrl-D at the prompt.

Fix: if piping is legitimate, wrap the call:

try:
    name = input("Name: ")
except EOFError:
    name = "anonymous"

In the browser editor on these docs, the runtime simulates input; you won't hit this there.

IndentationError and SyntaxError

IndentationError: expected an indented block after function definition on line 2

These are special — they fire before your program runs. Python refused to parse the file.

  • IndentationError — the body of a def, if, for, etc. is missing or misaligned. Most editors visualise indentation; turn on "show whitespace" to catch mixed tabs and spaces.
  • SyntaxError — you forgot a colon, mismatched a parenthesis, or misspelled a keyword. Recent Python versions point an arrow (^) at the offending character.

Fix: the error message names the line. Go look. If nothing's obviously wrong on that line, check the line above — an unclosed paren a few lines up often shows as a syntax error much later.

RuntimeError

A catch-all for "something went wrong at runtime that isn't one of the more specific errors." RecursionError (exceeded the recursion depth) is a common specialisation. Library code often raises RuntimeError when it's in a bad state.

Fix: read the message; it's usually descriptive. If recursion is the cause, either convert to an iterative loop or raise sys.setrecursionlimit in rare cases.

Before reaching for a real debugger, print() — or better, the f"{var=}" form — catches most bugs:

main.py
Output
Click Run to see the output here.

f"{var=}" prints both the expression source and its value, so you don't have to retype the name in the format string. Run the script, scan the output, find the line where a value became wrong. Most "mystery" bugs become obvious within three or four well-placed prints.

Clean up the prints before committing. logging.debug(...) is nicer than print for code you'll ship — you can turn debug logging on and off without editing lines.

breakpoint() and pdb

When print isn't enough, breakpoint() drops you into Python's interactive debugger at that point:

def discount(price, percent):
    breakpoint()
    return price * (1 - percent / 100)

discount(100, 20)

Run the script in a real terminal. You'll land at a (Pdb) prompt. A few commands to know:

  • p variable — print a variable.
  • n — step to the next line.
  • s — step into a function call.
  • c — continue running until the next breakpoint or the end.
  • q — quit.
  • l — list source around the current line.

IDE debuggers (VS Code, PyCharm) wrap the same protocol in a GUI — breakpoints set in the margin, a sidebar showing variables. Pick whichever feels lower-friction.

Habits That Reduce the Errors You Hit

  • Use descriptive variable names. Half of TypeError and AttributeError noise goes away when you can't forget what's in a variable.
  • Validate inputs at the boundary. Parse and check user input / file contents once, at the top of the function. The rest of the code can then trust the values.
  • Fail loudly, not silently. A bare except Exception: pass hides the errors you actually need to see. Catch specific exceptions, handle them deliberately, and let the rest propagate.
  • Read the bottom of the traceback first. Every minute spent learning to read tracebacks pays back a hundredfold.

Most errors aren't mysteries — they're one-line typos or wrong-type mistakes with a clear message. Trust the error message; it's usually right.

You've Made It

That's the end of the reference section. You've gone from "what is Python?" through variables, control flow, collections, functions, classes, iteration, real-world data, and errors. From here the next steps are project-shaped: pick something you want to build and work backwards to the pieces you need to learn more deeply. These pages will still be here when you come back with a specific question.

Frequently Asked Questions

What is a KeyError in Python?

KeyError is raised when you look up a dict key that doesn't exist. users["missing"] raises KeyError: 'missing'. The safe alternatives are users.get("missing", default), users.get("missing") (returns None), or an explicit if key in users: check.

What is an EOFError in Python?

EOFError (end-of-file) is raised when input() can't read anything because the input stream closed. You'll see it most often when a script that uses input() is piped without data, or when you hit Ctrl-D in the interactive prompt. Guard with try/except EOFError if your script must handle piped input.

What is a ModuleNotFoundError?

ModuleNotFoundError means import X didn't find a module named X. Either the package isn't installed (pip install X), or it's installed in a different Python than the one running your code (very common when you have multiple Pythons). python -m pip install X fixes the second case by using the same interpreter.

How do I read a Python traceback?

Read it from the bottom up. The last line is the exception type and message — the specific thing that went wrong. The lines above show the call stack that led there, with your own code usually closer to the bottom. Click or jump to the file + line in the bottom-most frame that's yours; that's where the fix goes.

Learn to code with Coddy

GET STARTED