Python context in Implicit Exception Chaining

This article explains the purpose and contents of the __context__ attribute in Python's exception handling mechanism, specifically during implicit exception chaining. It covers what object is assigned to __context__, the conditions under which the Python runtime populates it, and how it directly influences the tracebacks displayed during unhandled errors.

What is Stored in __context__?

In Python, the __context__ attribute of an implicitly chained exception stores a reference to the previous exception instance that was active when the new exception occurred.

Whenever an unhandled exception is raised inside an except block or a finally clause, Python automatically preserves the context of the original failure. The newly raised exception's __context__ attribute is set directly to the original exception object, creating a linked history of errors.

How Implicit Chaining Works

Implicit exception chaining happens automatically without requiring the from keyword. Consider the following example:

try:
    1 / 0
except ZeroDivisionError as original_error:
    # A new exception occurs while handling ZeroDivisionError
    int("invalid_number")

In this code:

  1. A ZeroDivisionError is raised.
  2. Inside the except block, Python attempts to run int("invalid_number"), which raises a ValueError.
  3. Because the ValueError was raised while ZeroDivisionError was actively being handled, Python automatically assigns the ZeroDivisionError instance to ValueError.__context__.

You can inspect this attribute programmatically:

try:
    try:
        1 / 0
    except ZeroDivisionError:
        int("invalid_number")
except ValueError as second_error:
    print(type(second_error.__context__))
    # Output: <class 'ZeroDivisionError'>
    print(second_error.__context__)
    # Output: division by zero

Traceback Representation

When an exception with a populated __context__ reaches the top of the call stack unhandled, Python's default traceback printer displays both exceptions in chronological order.

Between the tracebacks, Python inserts the following message:

During handling of the above exception, another exception occurred:

This diagnostic output informs the developer that the subsequent error was not an isolated incident, but occurred while attempting to recover from or clean up after the primary error.

__context__ vs. __cause__

Python differentiates between implicit and explicit exception chaining using two distinct attributes:

When explicit chaining is used (raise ... from ...), Python sets __cause__ to the specified exception and sets __suppress_context__ = True. This signals the traceback printer to show the message "The above exception was the direct cause of the following exception:" instead of the implicit context message. If no explicit cause is provided, __cause__ remains None, and the interpreter falls back to displaying __context__.