Skip to the solution
MediumBackend12 min read

What is except* and ExceptionGroup in Python 3.11+?

151 views

The problem

Question presented to candidate: "Python 3.11 added ExceptionGroup and a new except* syntax. What problem do they solve, and how does except* behave differently from a normal except when a group contains several different errors?"

What a strong answer should cover:

  • The problem: concurrent tasks or bulk validation can fail in several unrelated ways at once, and a normal exception can only report one; ExceptionGroup(message, [exc, ...]) carries them all (PEP 654, Python 3.11)
  • except* T matches the leaves of the group by type, at any nesting depth, and binds a new group holding only the matching leaves; several except* clauses can run for one group
  • Leaves that no clause matches are re-raised as a group, preserving the nesting; a plain exception caught by except* arrives wrapped in a group
  • Rules: you cannot mix except and except* on one try; break, continue and return are not allowed inside except*; except* ExceptionGroup is a TypeError
  • ExceptionGroup is an Exception; BaseExceptionGroup is used when a leaf is a BaseException such as KeyboardInterrupt
  • Where groups come from in practice: asyncio.TaskGroup (3.11), and the exceptiongroup backport for older Pythons

Code / implementation expected: Yes β€” raise a group of two or three different errors and handle them with separate except* clauses, showing what each handler receives.

  • exceptions
  • except-star
  • python3.11

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

12 min read Β· 10 sections

Run the code

Edit the code and run it here. Each console line with an expected value becomes a test.

PythonRaising a group and splitting it with except*
PythonThe rules: no mixing, no return, first match per leaf, errors raised in a handler
Pythonasyncio.TaskGroup raising an ExceptionGroup (needs a real event loop)
import asyncio

# Real-world source of groups: asyncio.TaskGroup (3.11+).
async def fetch(name, delay, fail_with=None):
    await asyncio.sleep(delay)
    if fail_with:
        raise fail_with
    return name + " ok"

async def main():
    try:
        async with asyncio.TaskGroup() as tg:
            t1 = tg.create_task(fetch("users", 0.01))
            tg.create_task(fetch("orders", 0.02, ValueError("orders: bad JSON")))
            tg.create_task(fetch("stock", 0.02, ConnectionError("stock: refused")))
        print("not reached")
    except* ValueError as eg:
        print("parse errors:", [str(e) for e in eg.exceptions])
    except* ConnectionError as eg:
        print("network errors:", [str(e) for e in eg.exceptions])
    print("users task finished first:", t1.result())

asyncio.run(main())

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 108 of 139 in Python

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Python questions
Up nextMedium

What is the difference between concurrency and parallelism in Python?

Continue