Python Exception Groups
An exception group is one exception that bundles several exceptions together. The group reports every failure at once.
Build a group
A group has a name and a list of errors. Its text form reports how many errors it holds.
errors = [ValueError("Name is empty"), TypeError("Age must be a number")]
group = ExceptionGroup("form problems", errors)
print(str(group))
print(len(group.exceptions))Raise and catch a group
A group travels like any exception. A plain except catches the whole bundle at once.
try:
raise ExceptionGroup("checks", [ValueError("Bad name"), ValueError("Bad city")])
except ExceptionGroup as group:
print(len(group.exceptions))
for err in group.exceptions:
print(err)Catch one type with except*
Each except* block takes only its own type. The rest of the group moves to the next block.
try:
raise ExceptionGroup("form", [ValueError("Name is empty"), TypeError("Age is text"), ValueError("City is empty")])
except* ValueError as group:
print("Value errors:", len(group.exceptions))
except* TypeError as group:
print("Type errors:", len(group.exceptions))Leftovers keep travelling
An except* block leaves other types behind. The leftovers form a smaller group, raised again.
try:
try:
raise ExceptionGroup("form", [ValueError("Name is empty"), TypeError("Age is text")])
except* ValueError as group:
print("Handled:", len(group.exceptions))
except ExceptionGroup as group:
print("Left over:", len(group.exceptions))
print(type(group.exceptions[0]).__name__)Example
def check_form(name, age, email, visits):
errors = []
if name == "":
errors.append(ValueError("Name is empty"))
if not age.isdigit():
errors.append(TypeError("Age must be a number"))
if "@" not in email:
errors.append(ValueError("Email needs an @ sign"))
if visits < 0:
errors.append(ValueError("Visits cannot be negative"))
if errors:
raise ExceptionGroup("Form has problems", errors)
print("Form is fine")
try:
check_form("", "ten", "ada.example.com", -1)
except* ValueError as group:
print("Value problems:", len(group.exceptions))
for err in group.exceptions:
print(err)
except* TypeError as group:
print("Type problems:", len(group.exceptions))
for err in group.exceptions:
print(err)Key points
- Exception group: one exception that bundles several exceptions together (Python 3.11+)
- Use ExceptionGroup(name, errors) to build a group from a list of errors
- Use group.exceptions to read the bundled errors as a tuple
- Use except* to catch only the errors of one type from a group
- Unmatched errors stay in a smaller group and are raised again afterwards
In this example, check_form checks all four fields, even after one fails. The empty name adds a ValueError to the list. The word ten is not digits, so the age check adds a TypeError. The email has no @ sign, so it adds another ValueError. The negative visits count adds one more ValueError. Because the list is not empty, the function raises one ExceptionGroup. The first except* block takes the three ValueError items and prints them. The second except* block takes the single TypeError and prints it.
Note
One try can hold several except* blocks, but plain except catches a group only as a whole.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Python Playground
Exercise
A group holds two ValueError items and one TypeError item. What does except* ValueError receive?