Skip to content

Raising & Chaining Exceptions

In professional Python code, you don’t just wait for errors to happen; you raise them yourself to enforce business logic. If a user enters an age of -5, Python doesn’t care, but your application should.

Using the raise keyword allows you to turn logical failures into standard Python exceptions that can be handled gracefully by other parts of your system.


You can trigger any built-in or custom exception using raise.

validation.py
def set_temperature(celsius):
if celsius < -273.15:
raise ValueError("Temperature below absolute zero is impossible!")
return celsius
try:
set_temperature(-300)
except ValueError as e:
print(f"Validation Failed: {e}")

Sometimes you want to catch one exception and raise a different, more descriptive one. However, you don’t want to lose the original error information (the “Root Cause”).

If you raise an exception inside an except block, Python automatically tracks the “Cause.”

You can use the from keyword to link exceptions.

chaining.py
def get_config():
try:
with open("config.json") as f:
return f.read()
except FileNotFoundError as e:
# We wrap the FileNotFoundError in a custom ApplicationError
raise RuntimeError("Application failed to start") from e

Output Traceback:

FileNotFoundError: [Errno 2] No such file or directory: 'config.json'
The above exception was the direct cause of the following exception:
RuntimeError: Application failed to start

If the original error is sensitive (e.g., contains a database password) or irrelevant, you can hide it.

raise ValueError("Invalid credentials") from None

For large applications, you should create your own exception classes. This allows users of your code to catch your errors specifically without catching every other generic error.

custom_errors.py
class AppError(Exception):
"""Base class for all errors in this app."""
pass
class DatabaseError(AppError):
"""Errors related to database connectivity."""
pass
class AuthError(AppError):
"""Errors related to user login."""
pass
# You can now catch all app errors at once,
# or just specific ones.
try:
login_user()
except AppError:
# This catches both DatabaseError and AuthError
show_friendly_message()

When an exception is raised, Python creates a Traceback Object (__traceback__). This object is a linked list of every function call that was currently active on the stack.

When you raise an exception, Python starts “unwinding” the stack, looking for a matching except block. If it doesn’t find one, it prints the traceback, showing you the exact file and line number of every step that led to the crash.