{"record":{"id":"d9e86cfea78511cb","repo":"python/cpython","slug":"taskgroup-self-r-is-shutting-down","errorCode":null,"errorMessage":"TaskGroup {self!r} is shutting down","messagePattern":"TaskGroup (.+?) is shutting down","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/taskgroups.py","lineNumber":226,"sourceCode":"\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\")\n        if self._exiting and not self._tasks:\n            coro.close()\n            raise RuntimeError(f\"TaskGroup {self!r} is finished\")\n        if self._aborting:\n            coro.close()\n            raise RuntimeError(f\"TaskGroup {self!r} is shutting down\")\n        task = self._loop.create_task(coro, **kwargs)\n\n        futures.future_add_to_awaited_by(task, self._parent_task)\n\n        # Always schedule the done callback even if the task is\n        # already done (e.g. if the coro was able to complete eagerly),\n        # otherwise if the task completes with an exception then it will cancel\n        # the current task too early. gh-128550, gh-128588\n        self._tasks.add(task)\n        task.add_done_callback(self._on_task_done)\n        try:\n            return task\n        finally:\n            # gh-128552: prevent a refcycle of\n            # task.exception().__traceback__->TaskGroup.create_task->task\n            del task\n\n    # Since Python 3.8 Tasks propagate all exceptions correctly,","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/taskgroups.py#L208-L244","documentation":"RuntimeError raised by TaskGroup.create_task() when the group is aborting (_aborting), i.e. a child task failed and the group is cancelling all siblings during teardown. Accepting new work during shutdown would leak a task no one awaits, so the coroutine is closed and the error raised.","triggerScenarios":"tg.create_task() executed after another child raised an exception (or the group was cancelled) while __aexit__ is cancelling remaining tasks; typical with done-callbacks, external queues draining into create_task, or code racing the abort.","commonSituations":"Retry/reschedule logic triggered by a failing task that tries to re-enqueue work into the now-aborting group; a supervisor loop polling 'should I spawn more' that wins the race against an error-triggered shutdown; multiplexed workers fed from an external producer.","solutions":["Handle failures inside task bodies (catch and decide) instead of reacting from outside with more create_task calls","If work must continue after a failure, run it outside the failed group in a new TaskGroup or as an independent task","Check group state assumptions: anything that can call create_task after the body's last await must be restructured to run within the body"],"exampleFix":"// before\nasync with asyncio.TaskGroup() as tg:\n    tg.create_task(worker(queue))\n# elsewhere, reacting to a worker error:\ntg.create_task(worker(queue))  # group is aborting -> RuntimeError\n\n// after\nasync def resilient_worker(queue):\n    while True:\n        item = await queue.get()\n        try:\n            await handle(item)\n        except Exception:\n            log.exception('item failed')  # keep the group alive\nasync with asyncio.TaskGroup() as tg:\n    tg.create_task(resilient_worker(queue))","handlingStrategy":"validation","validationCode":"null","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Handle per-item failures inside task bodies; do not react to failures by spawning into the aborting group","Design supervisors so spawning only happens while the body is awaiting, not from external callbacks","For work surviving a failure, move it to a fresh TaskGroup"],"tags":["asyncio","taskgroup","shutdown","structured-concurrency"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}