PythonMastery
reference 5 min read · lesson 15 of 25 in Reference

Python Built-in Exceptions Cheat Sheet

1 · The lesson

read

An exception is Python's way of saying "this went wrong": a missing key, a bad number, a file that is not there. Python passes the error back up through the function calls until an except for its class catches it. If nothing catches it, the program stops and prints a traceback (the list of calls that led to the error). This page shows how to catch, raise and define exceptions. For the full tutorial, see Exceptions and Exceptions basics.

1. Catch

Put the line that can fail in try, and say in except which error you expect. Catch only the errors you can actually handle.

python
text = "abc"
try:
    n = int(text)
except ValueError:
    n = 0
print(n)  # 0

except (KeyError, IndexError): with a tuple catches any of the listed errors. as e gives you the error object, and str(e) is its message:

python
nums = [1, 2]
try:
    nums[5]
except IndexError as e:
    print(str(e))  # list index out of range

A try statement can have two more parts. else runs only if there was no error. finally always runs, error or not, so it is the place for clean-up such as closing a connection.

python
for text in ["21", "abc"]:
    try:
        n = int(text)
    except ValueError:
        print("not a number")
    else:
        print(n * 2)       # only if there was no error
    finally:
        print("done")      # always runs
python
42
done
not a number
done

2. Raise

Use raise to report a problem in your own code. Raise an error object with a message that tells the reader what was wrong.

python
def set_age(age):
    if age < 0:
        raise ValueError(f"age must be 0 or more, got {age}")
    return age

try:
    set_age(-1)
except ValueError as e:
    print(e)  # age must be 0 or more, got -1

Inside an except block, a plain raise raises the same error again with its traceback. To raise a different error, add from e: Python then keeps the first error as the cause and shows both in the traceback.

python
def load(path):
    try:
        return open(path, encoding="utf-8").read()
    except OSError as e:
        raise RuntimeError(f"could not load {path}") from e

try:
    load("app.cfg")
except RuntimeError as e:
    print(e)                          # could not load app.cfg
    print(type(e.__cause__).__name__)  # FileNotFoundError
LineWhen to use it
raiseInside except: let the same error continue after logging it
raise NewError(...) from eTurn a low-level error into one that makes sense to your caller
raise NewError(...) from NoneHide the cause. Use this rarely
raise NotImplementedErrorIn a method that each subclass must write
sys.exit("no input file")Print the message and stop the program with exit code 1

3. Look inside an error

python
e = KeyError("b")
print(e.args)                       # ('b',)
print(str(e))                       # 'b'
print(type(e).__name__)             # KeyError
print(repr(e))                      # KeyError('b')
print(isinstance(e, LookupError))   # True

args holds the values passed when the error was raised. A KeyError message is the key in quotes. repr(e) shows the class and the message, which is the most useful form in a log. isinstance() is also true for subclasses (classes built on that class), so use it instead of type(e) == ....

4. Your own exceptions

Give your program its own error classes so callers can catch exactly your errors. Make each class a subclass of Exception, that is, a class built on Exception. Never build on BaseException. Make one base class, then more specific ones under it.

python
class AppError(Exception):
    """Base for this app's errors."""

class NotFound(AppError):
    pass

class HTTPError(AppError):
    def __init__(self, code):
        super().__init__(f"HTTP {code}")
        self.code = code            # extra data is stored as attributes

print(issubclass(NotFound, AppError))  # True
print(str(HTTPError(404)))             # HTTP 404
print(HTTPError(404).code)             # 404

Because NotFound and HTTPError are subclasses of AppError, except AppError: catches all three.

5. What catches what

Exceptions form a family tree. An except catches the class you name and every class below it. Here are the common branches:

python
BaseException
 +-- SystemExit                 (sys.exit())
 +-- KeyboardInterrupt          (Ctrl+C)
 +-- Exception                  <-- catch this, not BaseException
      +-- ArithmeticError
      |    +-- ZeroDivisionError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- OSError               (files, folders, network)
      |    +-- FileNotFoundError
      |    +-- FileExistsError
      |    +-- PermissionError
      |    +-- TimeoutError
      |    +-- ConnectionError
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- NameError
      |    +-- UnboundLocalError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- ValueError
      |    +-- UnicodeDecodeError
      +-- TypeError
      +-- AttributeError
      +-- StopIteration
      +-- ExceptionGroup        (3.11+)
python
print(issubclass(KeyError, LookupError))       # True
print(issubclass(PermissionError, OSError))    # True
print(issubclass(SystemExit, Exception))       # False

So except LookupError catches both KeyError and IndexError, and except OSError catches every file, disk and network error. except Exception does not catch sys.exit() or Ctrl+C, which is what you want. except Exception as e: is the widest catch you should write: use it at the top level of a program, and log the error.

6. Errors you will meet

This loop runs each line of code and prints the name of the error it raises.

python
import json

d = {"a": 1}
nums = [1, 2]
for code in ['int("3.5")', '"age: " + 3', 'd["b"]', 'nums[5]', 'None.upper()',
             'totl', '1 / 0', 'next(iter([]))', 'json.loads("{bad")']:
    try:
        eval(code)
    except Exception as e:
        print(f"{code:20} {type(e).__name__}")
python
int("3.5")           ValueError
"age: " + 3          TypeError
d["b"]               KeyError
nums[5]              IndexError
None.upper()         AttributeError
totl                 NameError
1 / 0                ZeroDivisionError
next(iter([]))       StopIteration
json.loads("{bad")   JSONDecodeError
ErrorWhat it meansUsual fix
ValueErrorThe type is right but the value is wrong, like int("3.5")Check the input. Catch it around the conversion
TypeErrorThe wrong type for the operation, like "age: " + 3Convert first: "age: " + str(3)
KeyErrorThe key is not in the dictd.get("b") gives None instead
IndexErrorThe position is past the end of the listCheck len(nums). The last item is nums[-1]
AttributeErrorThe object has no such attribute. Often a function returned NoneCheck what the function returns
NameErrorA typo, or a name used before it is assignedFix the spelling, or assign it first
ZeroDivisionErrorDivision by zeroCheck the divisor before dividing
StopIterationnext() found nothing leftnext(it, default) returns the default instead
FileNotFoundErrorThe file is not there. A relative path starts where Python runsCheck the name and Path.cwd()
JSONDecodeErrorThe text is not valid JSON. It is a kind of ValueErrorexcept ValueError catches it too
RecursionErrorA function keeps calling itself with no way to stopAdd a stopping case, or use a loop
ModuleNotFoundErrorThe module is not installed, or the name is wrongpip install it, or fix the name

Every one of these is explained in detail on the errors page.

7. Useful tools

python
import logging
import os
from contextlib import suppress

# Ignore one expected error, on purpose
with suppress(FileNotFoundError):
    os.remove("cache.tmp")

# Add a note: notes are printed under the traceback
e = ValueError("bad row")
e.add_note("in data.csv, line 3")
print(e.__notes__)  # ['in data.csv, line 3']

# Log the message and the full traceback
try:
    1 / 0
except ZeroDivisionError:
    logging.exception("sum failed")

assert n > 0, "n must be positive" checks your own logic while you develop. Python skips every assert when it runs with python -O, so never use it to check user input.

8. Exception groups (3.11+)

When several tasks fail at once, you can raise them together in an ExceptionGroup. Each except* handles the errors of its own type from the group.

python
try:
    raise ExceptionGroup("batch", [ValueError("bad row 3"), OSError("disk full")])
except* ValueError as eg:
    print("bad data:", eg.exceptions)
except* OSError as eg:
    print("disk problem:", eg.exceptions)
python
bad data: (ValueError('bad row 3'),)
disk problem: (OSError('disk full'),)

Common mistakes

Bare except:. An except with no class also catches Ctrl+C and sys.exit(), so the program will not stop. Fix: write except Exception:.

except Exception: pass. This hides every bug and prints nothing. Fix: log the error, or catch a narrower class.

Wide except before narrow except. In except Exception: ... followed by except ValueError: ..., the second one never runs, because the first already caught everything. Fix: put the narrow class first.

Losing the traceback. raise AppError(str(e)) drops the original error. Fix: raise AppError(...) from e.

Looking for .message. Python 3 errors have no .message attribute:

python
e = ValueError("bad")
print(hasattr(e, "message"))  # False
print(str(e))                 # bad

A long try block. Forty lines inside one try means you cannot tell which line failed. Fix: put only the risky line inside try.

assert for user input. python -O removes every assert. Fix: if age <= 0: raise ValueError(...).

Using e after the except block. Python deletes e when the block ends, so print(e) afterwards raises NameError. Fix: save it in another variable inside the block.

except ValueError or TypeError:. Python works out ValueError or TypeError first, and the result is just ValueError, so a TypeError is not caught:

python
try:
    "age: " + 3
except (ValueError, TypeError) as e:   # fix: use a tuple
    print(type(e).__name__)            # TypeError

return inside finally. A return in finally throws away any error from the try block. Never return from finally.

See also

Practice this

on practicepython.in

Short exercises that run in your browser and tell you what your code did, as well as whether a test passed.

Found this useful? Share it with a friend who’s learning Python.