Learn by reading through in order

Raising Exceptions with raise / Custom Exception Classes

Throw your own exceptions in Python with raise and define custom exception classes — every example runs in your browser.

In the previous article on try / except, we looked at the receiving side of an exception.

This article covers raise — the throwing side, where you surface an exception yourself. When you raise an exception on invalid input or an unexpected state, the caller is guaranteed to notice via try / except.

The basics of raise

Writing raise ExceptionClass("message") raises that exception right then. The moment raise executes, the rest of the code is skipped and control jumps to the matching except.

The message is optional, but including why it failed lets the receiver read it out via except ... as e.

raise → except flow
run the try bodyraise ValueError("...")(rest of try skipped)except ValueError as ee receives the messagecontinue runningjump
# Raise a ValueError and catch it on the receiving side
try:
    raise ValueError("Invalid age")
    print("never reached")
except ValueError as e:
    print(f"Caught: {e}")
# Output: Caught: Invalid age

# Any built-in exception works as-is
# Common ones: ValueError / TypeError / KeyError / IndexError

Do the smallest round-trip of raise and try / except.

① Inside try, run raise KeyError("user_id not found").

② Catch it with except KeyError as e: and print "Kind: KeyError / Details: {e}" on one line.

③ After try / except, call print("Continuing…") to confirm the program didn't halt.

(The explanation appears once the code runs correctly.)

Python Editor

Run code to see output

Validating with if + raise

raise is used most often for input validation. When an if spots something invalid, immediately raise and return the call to the caller. This is an idiomatic technique in functions (covered later), where raising inside a function notifies the caller of bad arguments.

The flow — normal path runs through; abnormal path raises and halts — is the core pattern for validation in production code.

Validation flow with if + raise
receive inputcond 1: value invalid?raise ValueError(...)cond 2: type invalid?raise TypeError(...)all checks passedrun normal processingcaller's except catches itYesNoYesNo

Check the input one condition at a time; the instant something fails, raise and stop. Only when every condition passes does normal processing proceed. Since the first raise wins, the order of checks sets their priority.

# Validate a product price: 0 or below is an error
price = -500

try:
    if price < 0:
        raise ValueError(f"Price must be 0 or higher (got: {price})")
    if not isinstance(price, int):
        raise TypeError(f"Price must be an integer (got type: {type(price).__name__})")
    print(f"Registered: {price}")
except ValueError as e:
    print(f"Value error: {e}")
except TypeError as e:
    print(f"Type error: {e}")
# Output: Value error: Price must be 0 or higher (got: -500)

A rough guide to which built-in exception to raise: use ValueError when the value is off, TypeError when the kind (type) doesn't match what's expected, and KeyError / IndexError when the target key or element is missing from a dict or list.

Validate a username.

① Define user_name = "".

② Inside try, raise ValueError("Username is required") when user_name is an empty string, and ValueError("Username must be 20 characters or fewer") when len(user_name) > 20. If neither is the case, print "Registered: {user_name}".

③ Catch with except ValueError as e: and print "Input error: {e}".

Python Editor

Run code to see output

Defining a custom exception class

Built-in exceptions alone sometimes make it hard to tell which validation failed. Defining your own exception class lets you catch it precisely on the except side.

The shape is class ErrorName(Exception): with pass (empty) as the body — that's it. We'll cover classes in depth in the upcoming object-oriented programming chapter, but for exception classes this one line is plenty.

Defining and using a custom exception class
Exception(built-in parent)class OutOfStockError(Exception): passraise OutOfStockError("out of stock")except OutOfStockError as e:pull the notice message from econtinue runningset as parent (define)use the type
# Define a custom exception (1 line is enough)
class InvalidAgeError(Exception):
    pass

class DuplicateUserError(Exception):
    pass

registered_users = ["alice", "bob"]
new_user = "alice"
new_age = -1

try:
    if new_age < 0:
        raise InvalidAgeError(f"Age must be 0 or higher: {new_age}")
    if new_user in registered_users:
        raise DuplicateUserError(f"Already registered: {new_user}")
    print(f"Registered: {new_user}")
except InvalidAgeError as e:
    print(f"Age error: {e}")
except DuplicateUserError as e:
    print(f"Duplicate error: {e}")
# Output: Age error: Age must be 0 or higher: -1

Custom exceptions set Exception as the parent class

The Exception in parentheses names the parent class. Putting Exception there means your custom class automatically gets the standard exception features — it can carry a message, it's catchable by a generic except Exception, and so on. The parent / child mechanism itself (inheritance) is covered in the object-oriented programming chapter, but this one line is all you need to define an exception.

Make a dedicated "out of stock" exception and raise it during a purchase flow.

① Define class OutOfStockError(Exception): pass.

② Set up stock = {"apple": 3, "bread": 0} and want = "bread".

③ In try, when stock[want] == 0, raise OutOfStockError(f"Out of stock: {want}"); otherwise print "Purchased: {want}".

④ Catch with except OutOfStockError as e: and print "Notice: {e}".

Python Editor

Run code to see output

In this article you learned how to raise exceptions yourself with raise, the if + raise pattern for validation, and how to define a custom exception class with Exception set as the parent.

Next up, we'll look at def — which has shown up several times already — as a first-class topic and learn how to bundle and reuse logic with functions.

QUIZ

Knowledge Check

Answer each question one by one.

Q1What does the following code print?
try:
raise ValueError("NG")
print("A")
except ValueError as e:
print(e)
print("B")

Q2Which built-in exception is most appropriate when the value is invalid?

Q3What's the biggest benefit of using a custom exception class MyError(Exception): pass?