Programming · Python Errors

Top 25 Python Errors (And the 1-Line Fixes)

The mistakes everyone hits—explained in plain language with quick fixes.

Reading time: ~8–12 min
Level: All levels
Updated:

Python errors feel scary until you realize they’re mostly repeating patterns. Once you can read a traceback and recognize the usual suspects, debugging stops being a guessing game. This post is a practical “field guide” to the top 25 Python errors—with the 1-line fixes you can apply fast, plus a workflow that helps you prevent the same mistakes from coming back.


Quickstart

If you’re actively stuck on an error right now, do this in order. These steps are designed to get you from “it crashed” to “fixed + won’t regress” as quickly as possible.

1) Read the traceback from the bottom

The last line is the punchline: TypeError, NameError, KeyError, etc. Then look at the last frame in your code (not the standard library).

  • Start at the last line: exception type + message
  • Jump to the last “your file” entry in the stack
  • Confirm the variable values at that exact line

2) Make the crash reproducible

If you can’t reproduce it, you can’t reliably fix it. Try to run the smallest possible command that triggers the same error.

  • Save the exact input that caused the failure
  • Reduce to a minimal snippet (delete until it still breaks)
  • Re-run after each change (small steps)

3) Inspect values like a detective

Most Python errors are not “mysterious”—they’re “this value is not what you think it is.”

  • type(x) (is it a list, dict, None?)
  • repr(x) (hidden whitespace, quotes, escapes)
  • len(x), x.keys(), dir(x) (shape of the data)

4) Add a fast “guardrail”

Fix the bug, then add something that prevents it: an assertion, a type, a test, or a validation step.

  • Validate external inputs (files, JSON, user text)
  • Prefer explicit checks: if x is None:
  • Add a tiny test that reproduces the bug
Run Python in “louder” mode while debugging

Developer flags surface common issues earlier (warnings, resource leaks, faulthandler output). This won’t replace real debugging, but it shrinks your search space.

# create a clean environment (recommended for import/install issues)
python -m venv .venv
# macOS/Linux:
source .venv/bin/activate
# Windows (PowerShell):
# .\.venv\Scripts\Activate.ps1

python -m pip install -U pip
# optional: fast static checks (skip if you want pure stdlib)
python -m pip install -U ruff

# run with extra diagnostics
python -X dev -X faulthandler your_script.py
ruff check .
What counts as a “1-line fix”?

A 1-line fix is the smallest change that addresses the root cause (not a band-aid). Sometimes that line is “use the right method,” sometimes it’s “add a guard,” and sometimes it’s “import the correct symbol.” The sections below show the fix and the reasoning so you can generalize.

Overview

“Top 25 Python errors” isn’t about memorizing messages—it’s about learning the small set of mental models Python is enforcing: names must exist, types must match operations, indexes must be in range, keys must be present, and indentation must be consistent.

How to use this post (fast)

What’s inside

  • A repeatable debugging workflow (works for almost any exception)
  • The 25 most common Python errors with 1-line fixes
  • Pitfalls that create “weird” bugs (mutable defaults, shadowing, imports)
  • FAQ + a scan-fast checklist you can bookmark

What this is not

  • A list of random “gotchas” without context
  • A cheat sheet that ignores why the error happened
  • A “just wrap it in try/except” approach
Avoid the “fix the symptom” trap

If your “fix” is deleting an error by hiding it (blanket except:, returning defaults everywhere), you’ll ship bugs that are harder to diagnose later. Prefer fixes that make the data and control flow explicit.

Core concepts

The fastest debuggers don’t memorize messages—they understand what Python is trying to protect: predictable name lookup, consistent object behavior, and safe access to containers. These core concepts turn “random error strings” into a small set of categories.

1) Tracebacks are maps, not blame

A traceback is a stack of frames: “here’s where we were, and here’s how we got there.” The most useful frame is usually the last one inside your project. The bottom line tells you the exception type and message—treat it as a search query for your brain.

A quick way to interpret a traceback

Part What it means What you do
Exception type TypeError, NameError, etc. Classify the bug category
Message Often names the exact mismatch Verify variable types/values
Stack frames Call chain leading to the crash Jump to the last “your code” frame
Line of code The operation that failed Ask “what must be true for this to work?”

2) “Names” and scope rules are strict (and that’s good)

If Python says a name doesn’t exist (NameError) or is used before assignment (UnboundLocalError), it’s telling you exactly where your mental model diverges from reality. Scope is determined at compile time: if you assign to a name anywhere in a function, Python treats it as local unless declared global/nonlocal.

3) Types define what operations are legal

TypeError is Python’s way of saying: “this object doesn’t support that operation.” The fix is usually one of three things: convert the type, call the method you actually meant, or change the data shape. The fastest move is to print the type at the failing line.

4) Containers don’t guess: indexes and keys must exist

Lists/tuples care about indexes (IndexError), dicts care about keys (KeyError). In production code, you rarely want a crash on missing data—so you use guards: if key in d, d.get(key), if i < len(xs), or default values.

5) Imports depend on your environment, not your hopes

Many “ImportError” problems are really “I’m running a different Python than I think.” A virtual environment keeps dependencies consistent, and running with python -m helps ensure you’re using the same interpreter.

The most useful debugging question

At the failing line, ask: “What must be true for this to work?” Then verify those conditions with prints, assertions, or a debugger.

Step-by-step

This is a practical workflow you can apply to almost any Python exception. It’s intentionally boring—because boring workflows are repeatable, and repeatable workflows ship code.

Step 1 — Confirm the failing line and the failing value

Go to the last frame in your code and look at the exact operation. Then confirm the value(s) on that line (type, repr, shape). If you want a single best tool built into Python, it’s the debugger hook: breakpoint().

def debug_here(**vars_to_watch):
    # tiny helper: call with debug_here(x=x, y=y) to see types and reprs
    for k, v in vars_to_watch.items():
        print(f"{k}: type={type(v).__name__}, repr={v!r}")

def parse_port(value):
    # common crash: ValueError when value isn't numeric
    debug_here(value=value)
    if value is None:
        return 0  # 1-line fix: guard None explicitly
    return int(str(value).strip())  # 1-line fix: normalize before int()

# Use breakpoint() when the bug isn't obvious from prints
def handler(payload):
    port = payload.get("port")
    breakpoint()  # drop into debugger: inspect payload, port, etc.
    return parse_port(port)
Debugger tip

In the debugger, you usually want three checks first: type(x), x, and x!r (repr). Many “impossible” bugs are whitespace, None, or the wrong container shape.

Step 2 — Apply the smallest correct fix

A good fix changes the program so the bad state can’t occur (or is handled explicitly). Below are the Top 25 Python errors you’ll see in real code, each with a 1-line fix and a short “why.”

Top 25 Python errors and the 1-line fixes

# Error (common message) What it usually means 1-line fix (typical)
1 SyntaxError Python can’t parse the code Fix the token: missing :, quote, bracket, or bad indentation
2 IndentationError Mixed tabs/spaces or wrong block alignment Convert tabs → spaces and align blocks (most editors: “convert indentation”)
3 NameError: name x is not defined Variable/function wasn’t created in this scope Define it or pass it in: def f(x): ... / x = ...
4 UnboundLocalError You assign to a name in a function, making it local, but read it first Initialize before use: x = None (or add nonlocal/global if intended)
5 TypeError: ‘NoneType’ object is not ... You’re operating on None Guard: if x is None: return ...
6 TypeError: can only concatenate str (not "int") to str Mixing types in string operations Convert: msg = "n=" + str(n) (or use f-strings)
7 TypeError: 'str' object is not callable You overwrote a function name with a string (shadowing) Rename the variable (e.g., don’t use str, list, open)
8 TypeError: 'int' object is not subscriptable You used [...] on a non-container Use the right value: ensure x is a list/dict, or drop the index
9 AttributeError: 'X' object has no attribute 'y' Wrong object type, wrong attribute, or None Check type/None first: assert obj is not None (or call correct method)
10 IndexError: list index out of range Index is outside list bounds Guard: if i < len(xs): ... (or iterate directly)
11 KeyError: 'missing' Dict key doesn’t exist Use d.get("missing") or check if key in d
12 ValueError: invalid literal for int() Conversion failed (bad format) Normalize input: int(str(x).strip()) (or validate with isdigit())
13 ValueError: too many values to unpack Unpacking expects fewer items than provided Match arity: a, b, *rest = items
14 ValueError: not enough values to unpack Unpacking expects more items than provided Provide defaults: a, b = (items + [None, None])[:2] (or check length)
15 ZeroDivisionError Division by zero Guard: if denom == 0: return 0 (or raise a clearer error)
16 ImportError: cannot import name ... Wrong symbol name, circular import, or version mismatch Import the module then access: import pkg; pkg.name (or fix circular import)
17 ModuleNotFoundError Package not installed in this interpreter/venv Install via the same Python: python -m pip install package
18 FileNotFoundError Path is wrong or relative path differs Use an absolute path (or build relative to __file__)
19 PermissionError OS denies access to file/dir Write to a permitted location (or fix permissions)
20 IsADirectoryError You tried to open a directory as a file Point to a file path (or list directory contents)
21 UnicodeDecodeError Wrong encoding assumption when reading bytes Specify encoding: open(path, encoding="utf-8")
22 JSONDecodeError Invalid JSON (trailing commas, single quotes, partial file) Validate/print raw content; ensure strict JSON formatting
23 AssertionError An assertion condition failed Fix the violated assumption or replace assert with explicit error handling
24 RecursionError: maximum recursion depth exceeded Unbounded recursion or cycles Add a base case (or switch to an iterative loop)
25 RuntimeError: event loop is closed / already running Async loop misuse (often in notebooks) Use await in async contexts; avoid nested asyncio.run()

Step 3 — Prevent the bug from returning

After you apply the 1-liner, add a small guardrail. The goal isn’t “never fail”—it’s “fail clearly, early, and in the right place.”

Guardrails that pay off fast

  • Add input checks at boundaries (files, JSON, HTTP)
  • Prefer d.get(key) when missing keys are normal
  • Use breakpoint() for non-obvious state bugs
  • Write one regression test per “real crash”

Signals you fixed the root cause

  • You can explain the bug in one sentence
  • You can reproduce it reliably (before) and not (after)
  • The fix reduces ambiguity (clear types, clear guards)
  • You didn’t hide the error with a blanket exception

Common mistakes

The errors above are the symptoms. These are the patterns that cause them repeatedly. Fixing these habits once can remove a surprising amount of day-to-day debugging.

Mistake 1 — Shadowing built-ins (list, str, dict)

You assign str = "hello" and later try to call str(...). This creates “object is not callable” and similar confusion.

  • Fix: rename the variable (e.g., text, items, mapping).
  • Prevention: linters catch this early.

Mistake 2 — Mutable default arguments

Default args are evaluated once, not per call. That means data “leaks” between calls.

  • Fix: default to None and create inside the function.
  • Symptom: “why does my list keep growing?”
# BAD: the same list is reused across calls
def add_tag(tag, tags=[]):
    tags.append(tag)
    return tags

# GOOD: new list each time (1-line fix: default None + create inside)
def add_tag(tag, tags=None):
    tags = [] if tags is None else tags
    tags.append(tag)
    return tags

Mistake 3 — Using == vs is incorrectly

is checks identity (same object), not equality (same value). Use is for singletons like None.

  • Fix: if x is None: (not x == None).
  • Fix: for value comparison use ==.

Mistake 4 — Assuming external data always has the shape you expect

Most KeyError and TypeError issues come from unvalidated JSON, CSV, or user inputs.

  • Fix: validate at the boundary (presence, type, range).
  • Fix: use .get() with defaults when missing is normal.

Mistake 5 — Iterating by index when you don’t need to

Manual indexing is a common path to IndexError. Python gives you safer patterns.

  • Fix: iterate directly: for x in xs:
  • Fix: need the index? for i, x in enumerate(xs):

Mistake 6 — Catching exceptions too broadly

except Exception: can be appropriate at system boundaries, but inside core logic it hides root causes.

  • Fix: catch specific exceptions: except (ValueError, KeyError) as e:
  • Fix: log and re-raise when you can’t recover.

Mistake 7 — Relative-path surprises

Your working directory depends on how you run the program (IDE vs CLI vs cron). That’s why relative paths fail with FileNotFoundError.

  • Fix: build paths relative to the script (or configure a project root).
  • Fix: print the current dir once: os.getcwd() when debugging.

Mistake 8 — Running the wrong Python interpreter

“It works on my machine” often means “I installed it in a different interpreter.”

  • Fix: install with python -m pip ... (matches the running interpreter).
  • Fix: use a venv and activate it consistently.
A high-value habit

When you see a weird error, don’t “try random changes.” First, print type(x) and repr(x) at the failing line. You’ll fix more bugs in 30 seconds than in 30 minutes of guessing.

FAQ

How do I read a Python traceback correctly?

Start at the bottom: the final line tells you the exception type and message. Then go up to the last stack frame that points to your file. That line is where the failure happened; the earlier frames explain how you got there.

Why do I get ModuleNotFoundError even after installing the package?

You likely installed into a different Python interpreter than the one running your program. Use python -m pip install ... and a virtual environment to ensure install and runtime match.

What’s the difference between KeyError and AttributeError?

KeyError is for dictionaries when a key is missing (d["k"]). AttributeError is for objects when a property/method doesn’t exist (obj.k). If missing data is normal, use d.get("k") or validate earlier.

When should I use try/except?

Use it when you can recover (e.g., parsing user input, reading optional files) or at system boundaries (CLI entrypoint, API handler) to return a clean error message. Inside core logic, prefer guards and explicit checks; catch only specific exceptions you expect.

Why does Python say “object is not callable”?

It usually means you overwrote a function name with a variable (shadowing), or you forgot parentheses. Example: print = "oops" makes print("hi") fail. Rename the variable to restore the callable.

How do I stop errors from coming back after I fix them?

Add a guardrail: validate inputs, assert key invariants, write a tiny regression test, and avoid hiding exceptions. The goal is to turn “mystery crash” into “clear failure at the boundary.”

Cheatsheet

Bookmark this. It’s the quickest way to turn a scary traceback into an actionable fix.

Debugging flow (90 seconds)

  • Read the last line: exception type + message
  • Open the last frame in your code
  • Print: type(x) + repr(x) for the suspicious values
  • Ask: “What must be true for this line to work?”
  • Apply the smallest fix (conversion / guard / correct method)
  • Add a guardrail (validation, assertion, test)

Fast mapping: error → first thing to check

Error type First check Common 1-liner
NameError / UnboundLocalError Scope & where the name is assigned Initialize: x = None or pass parameter
TypeError type(x) at failing line Convert: str(x), int(...), or use correct method
KeyError Is the key present? Is data shape stable? d.get(key) or if key in d
IndexError Length vs index; why index exists at all if i < len(xs): or iterate directly
Import errors Which interpreter am I using? python -m pip install ... and venv
If you’re debugging in a hurry

Add breakpoint() at the failing line, inspect the exact values, and make one small change. Most bugs are “wrong type” or “unexpected None” in disguise.

Wrap-up

Python errors are mostly a friendly constraint system: names must exist, types must match operations, and containers don’t guess. Once you internalize those rules, the “Top 25 Python errors” stop being a list of scary messages and become a short set of patterns you can fix quickly and confidently.

Next time you hit an exception: read the last line, jump to your code frame, inspect the real values, apply the smallest fix, and add one guardrail so it doesn’t happen again. If you want to go deeper, check out the related posts below for faster Python, cleaner code structure, and async patterns that don’t bite.

Next actions

  • Save this post and keep the Cheatsheet open while you code
  • Pick 2 common errors you hit and add guardrails (validation + test)
  • Adopt one habit this week: avoid shadowing built-ins, or stop using mutable defaults

Quiz

Quick self-check (demo). This quiz is auto-generated for programming / python / errors.

1) You see a traceback. What should you look at first to find the real failure point?
2) What’s the most common cause of TypeError: 'str' object is not callable?
3) You got KeyError: 'status' on a dictionary. What’s the safest quick fix when missing keys are normal?
4) You see ModuleNotFoundError after installing a package. What’s the most likely issue?