Skip to content
Free public beta until December 4, 2026: every course is open, no card needed. After that, the first chapter of each course stays free and full access is a one-time $39 ($19 for up to 100 founding members chosen for helpful feedback). Your progress is kept. How the beta works

Ways to handle errors

Let it crash, check first, catch it, clean up with finally or with, raise your own, or log it. Who can do something about the problem decides which.

Ask who can actually do something about this problem?

  • Nobody: it's a bug → let the exception propagate and read the traceback. Catching it would only hide it.
  • The code right here can recover (a missing file means "use the defaults", bad input means "ask again") → try/except naming the exact exception type, around as few lines as possible.
  • Something must happen whether or not it failed (close a file, release a lock) → a with statement, or finally when there's no context manager for it.
  • Your function got input it can't work with → raise a ValueError or TypeError with a message, or your own exception class when callers need to tell your failures apart.
  • A long-running program must keep going but someone should know → catch at the top level and logging.exception(...), never a bare print.

Never write a bare except: or except Exception: pass. That turns every future bug into a silent wrong answer.

Reading what went wrong

Read the last line first, then the frame just above it.

Section

Debugging

Reproduce, narrow down, look with a debugger, then fix.

Catching and cleaning up

What each clause is for and when it runs.

with guarantees the cleanup, even when an exception escapes.

Raising and reporting

Fail loudly with a clear type and message.

Ask forgiveness or look before you leap, and how specific to make a handler.

Section

Logging

Record a failure with its traceback for whoever reads the log later.