Standard Way of Using Exception Chains in Python 3



In Python 3, exception chaining allows one exception to be raised while preserving the context of the original exception. This provides a complete track, which makes it easy to understand how an error occurred during debugging.

Python supports exception chaining explicitly using the raise ... from ... statement, or implicitly when a new exception is raised while handling another.

Using raise ... from ... Statement

This is the standard way to explicitly chain exceptions. The second exception is raised with a reference to the original exception using the from keyword, which helps to track the cause of the error.

Example: Chaining ValueError from ZeroDivisionError

In the following example, we are dividing by zero and then raising a new ValueError while explicitly chaining it from the original exception -

try:
   x = 1 / 0
except ZeroDivisionError as e:
   raise ValueError("Secondary error occurred") from e

We get the following output -

Traceback (most recent call last):
  ...
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  ...
ValueError: Secondary error occurred

Implicit Exception Chaining

When a new exception is raised inside an except block without using from, Python automatically links the exceptions using the context. This is known as implicit exception chaining.

Example: Implicit chaining in nested exception

In the following example, we are raising a TypeError inside an except block without using from, which leads to implicit chaining -

try:
   int("abc")
except ValueError:
   raise TypeError("Follow-up error occurred")

We get the following output -

Traceback (most recent call last):
  ...
ValueError: invalid literal for int() with base 10: 'abc'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  ...
TypeError: Follow-up error occurred

Suppressing Exception Context

In some cases, you may not want to show the original exception. You can suppress the exception context by setting from None when raising the new exception.

Example

In the following example, we are raising a new exception while explicitly removing the traceback of the original exception -

try:
   int("abc")
except ValueError:
   raise RuntimeError("Suppressed original exception") from None

We get the following output -

Traceback (most recent call last):
  ...
RuntimeError: Suppressed original exception

Best Practice for Exception Chaining

Use raise ... from ... when you want to keep the traceback for debugging and provide better context. Avoid implicit chaining when clarity is needed, and suppress it only when the original exception is irrelevant.

Example: Using custom exceptions with chaining

In the following example, we are using a custom exception class and chaining it from a built-in exception for better debugging -

class MyCustomError(Exception):
   pass

try:
   result = int("xyz")
except ValueError as e:
   raise MyCustomError("Custom conversion failure") from e

We get the following output -

Traceback (most recent call last):
  ...
ValueError: invalid literal for int() with base 10: 'xyz'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  ...
MyCustomError: Custom conversion failure
Updated on: 2025-05-26T13:35:13+05:30

254 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements