{"record":{"id":"94136c6b4d5cc5ad","repo":"python/cpython","slug":"unhandled-errors-in-a-taskgroup","errorCode":null,"errorMessage":"unhandled errors in a TaskGroup","messagePattern":"unhandled errors in a TaskGroup","errorType":"exception","errorClass":"BaseExceptionGroup","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/taskgroups.py","lineNumber":202,"sourceCode":"            # which will keep the cancel count stable.\n            if self._parent_task.cancelling():\n                self._parent_task.uncancel()\n                self._parent_task.cancel()\n            try:\n                # If the *only* error is a GeneratorExit from the body\n                # of the group, then instead of raising an\n                # ExceptionGroup we raise GeneratorExit. This ensures\n                # that async generators that use TaskGroup properly\n                # swallow the exception on `aclose()` while ensuring\n                # that no exceptions from subtasks are swallowed.\n                if (\n                    et is not None\n                    and issubclass(et, GeneratorExit)\n                    and len(self._errors) == 1\n                ):\n                    raise exc\n                else:\n                    raise BaseExceptionGroup(\n                        'unhandled errors in a TaskGroup',\n                        self._errors,\n                    ) from None\n            finally:\n                exc = None\n\n        # Suppress any remaining exception (exceptions deserving to be raised\n        # were raised above).\n        return True\n\n    def create_task(self, coro, **kwargs):\n        \"\"\"Create a new task in this group and return it.\n\n        Similar to `asyncio.create_task`.\n        \"\"\"\n        if not self._entered:\n            coro.close()\n            raise RuntimeError(f\"TaskGroup {self!r} has not been entered\")","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/taskgroups.py#L184-L220","documentation":"BaseExceptionGroup('unhandled errors in a TaskGroup') is raised from TaskGroup.__aexit__ when one or more child tasks finished with exceptions that nothing else re-raised. It bundles every child failure (plus any interaction with an in-flight exception 'et'); a special case re-raises a sole child exception during GeneratorExit so async generators close cleanly.","triggerScenarios":"One or more tasks created via tg.create_task() raise before the 'async with' block exits; also combined failures during group abort, where sibling cancellations and the original error are collected together.","commonSituations":"Structured-concurrency fan-out where one worker raises (network error, bug) and you did not catch it inside the task body; several workers failing simultaneously (e.g. shared dependency down) producing a multi-exception group; nested TaskGroups producing nested groups.","solutions":["Catch with except* (ExceptionGroup handling): 'except* ValueError as eg:' to handle each child failure type","Add try/except inside task bodies for expected per-task errors so the group only propagates truly fatal ones","Inspect eg.exceptions recursively to find root causes; log them before deciding on restart/abort"],"exampleFix":"// before\nasync with asyncio.TaskGroup() as tg:\n    tg.create_task(fetch(url))\n\n// after\ntry:\n    async with asyncio.TaskGroup() as tg:\n        tg.create_task(fetch(url))\nexcept* ValueError as eg:\n    for exc in eg.exceptions:\n        log.warning('fetch failed: %r', exc)","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"try:\n    async with asyncio.TaskGroup() as tg:\n        tg.create_task(fetch(u)) for u in urls]\nexcept* http.HTTPError as eg:\n    log.warning('http failures: %r', eg.exceptions)\nexcept* OSError as eg:\n    raise  # fatal, abort the batch","preventionTips":["Catch expected per-task failures inside the task body so the group only sees fatal errors","Use except* (not except ExceptionGroup) for typed handling of child failures","Log eg.exceptions recursively before deciding restart policy"],"tags":["asyncio","taskgroup","exception-group","structured-concurrency"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}