Custom exception classes & raise … from

Your own exceptions

Lesson 13 of 20 · 10 min · Module 4: When things go wrong

Built-in exceptions such as ValueError are general. Your own exception types let callers handle your errors precisely, and carry extra information.

Start this lesson →

Free. No installation: you write and run the code in your browser, and it is checked automatically.

By the end, you’ll be able to…

  • Define a custom exception
  • Store details on an exception
  • Chain exceptions with from

The idea

Create an exception by subclassing an existing one: class InvalidAgeError(ValueError). Code that catches ValueError still works, while new code can catch the specific type. raise NewError(...) from err keeps the original error as __cause__, which makes tracebacks much clearer.

class ConfigError(Exception):
    pass

try:
    raise ConfigError("missing port")
except ConfigError as err:
    print("config problem:", err)

01Subclass the closest built-in

Because InvalidAgeError inherits from ValueError, existing except ValueError blocks still catch it. Callers who care can catch InvalidAgeError specifically.

02Exceptions can carry data

An attribute such as value lets the code that catches the error show a precise message or highlight the right form field, without parsing the error text.

class InvalidAgeError(ValueError):
    def __init__(self, value):
        super().__init__(f"invalid age: {value!r}")
        self.value = value

print(InvalidAgeError("abc").value)
Output
abc

03Keep the cause

raise InvalidAgeError(...) from err stores the original exception in __cause__. A traceback then shows both errors, so you see what really went wrong.

Your turn

Define InvalidAgeError, a subclass of ValueError that stores the rejected input in a value attribute. Write parse_age(text): strip spaces, convert to int, and return it if it is between 0 and 130. Otherwise raise InvalidAgeError. When int() fails, chain its error with from.

What the checks look for

  • Parses valid ages
  • InvalidAgeError is a ValueError
  • Rejects text and out-of-range ages
  • Stores the input and chains the original error
Try it in the editor →

Take this with you

Specific exception types make errors easy to handle; from keeps their history.

Go a little further

Add a class AgeTooHighError(InvalidAgeError) and catch it separately to suggest checking for a typo.

Learn Python Intermediate for free

20 short lessons with real code and instant checks.

See the whole course →