Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

An ExceptionGroup (introduced in Python 3.11 via PEP 654) is a built-in exception type that allows multiple, independent exceptions to be raised and handled simultaneously. It acts as a container that aggregates a sequence of exception instances into a single tree-like structure, enabling the propagation of concurrent errors without suppressing any individual exception.

Class Hierarchy

The feature introduces two new built-in classes:
  • BaseExceptionGroup: Inherits from BaseException. It is instantiated if any exception within the group inherits from BaseException but not Exception (e.g., KeyboardInterrupt or SystemExit).
  • ExceptionGroup: Inherits from BaseExceptionGroup and Exception. It is instantiated only when all contained exceptions are subclasses of Exception.

Instantiation and Raising

An exception group is initialized with a string message and a sequence (typically a list) of exception instances. Groups can be nested to form a tree structure.

# Raising a flat ExceptionGroup
raise ExceptionGroup(
    "Multiple validation errors occurred",
    [
        ValueError("Invalid configuration parameter"),
        TypeError("Expected string, got integer")
    ]
)


# Raising a nested ExceptionGroup
raise ExceptionGroup(
    "System failure",
    [
        ConnectionError("Database timeout"),
        ExceptionGroup("File system errors", [PermissionError(), FileNotFoundError()])
    ]
)

Handling with except*

To handle exceptions, Python introduces the except* syntax. Unlike a standard except clause, which matches the exception object as a whole and stops, except* can structurally split exception groups and handle multiple branches independently.
try:
    # Raising a standard, single exception
    raise ValueError("Single error")
except* ValueError as e:
    # Python automatically wraps the single exception in an ExceptionGroup
    print(type(e))  # <class 'ExceptionGroup'>
    print(e.exceptions)  # (ValueError('Single error'),)

try:
    raise ExceptionGroup(
        "Errors", 
        [
            ValueError("A"), 
            ExceptionGroup("Nested", [TypeError("B"), ValueError("C")])
        ]
    )
except* ValueError as e:
    # Extracts ValueError("A") and ValueError("C") into a new ExceptionGroup tree,
    # preserving the original nested structure.
    pass
except* TypeError as e:
    # Extracts the remaining TypeError("B") into a new ExceptionGroup.
    pass
Mechanics of except*:
  1. Leaf-Node Evaluation: Exception matching in an except* clause is strictly evaluated only on the individual non-group exceptions (the leaves). The matching condition is never evaluated against the ExceptionGroup or BaseExceptionGroup containers themselves.
  2. Type Restrictions: Because except* matching applies only to leaf nodes, it is a TypeError to use ExceptionGroup, BaseExceptionGroup, or their subclasses as the target type in an except* clause.
  3. Splitting and Wrapping: If leaf exceptions match the specified type, the exception group is structurally split. The matched leaf exceptions are extracted into a new ExceptionGroup that preserves the original nested shape, which is then bound to the variable in the as clause. If a standard, single exception is caught, Python automatically wraps it in an ExceptionGroup before binding it.
  4. Fallthrough: Any unmatched leaf exceptions remaining in the original group are propagated to subsequent except* clauses. If exceptions remain after all except* blocks are evaluated, a new ExceptionGroup containing the unhandled exceptions is implicitly re-raised.
  5. Exclusivity: You cannot mix standard except and except* clauses in the same try block.

Internal API

Exception groups expose specific methods and attributes for programmatic inspection and manipulation:
  • exceptions: A tuple containing the direct child exceptions of the group.
  • split(condition): Structurally splits the exception group. The condition can be an exception type, a tuple of exception types, or a callable that takes an exception instance and returns a boolean. Unlike the except* syntax, the condition passed to split() is evaluated against exception group containers. If the condition returns True for an exception group itself, the entire group is included in the match, and its individual child exceptions are not evaluated further. It returns a tuple (match, rest), where match is an ExceptionGroup containing the exceptions that satisfy the condition, and rest is an ExceptionGroup containing the remainder. If no exceptions match, match is None; if all match, rest is None.
  • subgroup(condition): Similar to split(), but returns only the match component (an ExceptionGroup or None).
eg = ExceptionGroup("Errors", [ValueError(1), TypeError(2)])


# Splitting by exception type (or tuple of types)
match_type, rest_type = eg.split(ValueError)

print(type(match_type))  # <class 'ExceptionGroup'> containing ValueError
print(type(rest_type))   # <class 'ExceptionGroup'> containing TypeError


# Splitting by a callable condition
match_cb, rest_cb = eg.split(lambda e: str(e) == "2")
Master Python with Deep Grasping Methodology!Learn More