{"record":{"id":"d8001787803be8f4","repo":"python/cpython","slug":"taskgroup-self-r-cannot-determine-the-parent-tas","errorCode":null,"errorMessage":"TaskGroup {self!r} cannot determine the parent task","messagePattern":"TaskGroup (.+?) cannot determine the parent task","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/taskgroups.py","lineNumber":64,"sourceCode":"        if self._errors:\n            info.append(f'errors={len(self._errors)}')\n        if self._aborting:\n            info.append('cancelling')\n        elif self._entered:\n            info.append('entered')\n\n        info_str = ' '.join(info)\n        return f'<TaskGroup{info_str}>'\n\n    async def __aenter__(self):\n        if self._entered:\n            raise RuntimeError(\n                f\"TaskGroup {self!r} has already been entered\")\n        if self._loop is None:\n            self._loop = events.get_running_loop()\n        self._parent_task = tasks.current_task(self._loop)\n        if self._parent_task is None:\n            raise RuntimeError(\n                f'TaskGroup {self!r} cannot determine the parent task')\n        self._entered = True\n        if self._cancel_on_enter:\n            self.cancel()\n\n        return self\n\n    async def __aexit__(self, et, exc, tb):\n        tb = None\n        try:\n            return await self._aexit(et, exc)\n        finally:\n            # Exceptions are heavy objects that can have object\n            # cycles (bad for GC); let's not keep a reference to\n            # a bunch of them. It would be nicer to use a try/finally\n            # in __aexit__ directly but that introduced some diff noise\n            self._parent_task = None\n            self._errors = None","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/taskgroups.py#L46-L82","documentation":"RuntimeError raised by TaskGroup.__aenter__ when tasks.current_task() returns None, i.e. the code entering the group is not running inside a Task. TaskGroup relies on a parent task to attach cancellation semantics (child failures cancel the parent), so entering it from bare callback/loop context is unsupported.","triggerScenarios":"Awaiting tg.__aenter__ from code driven outside a Task: e.g. directly inside a loop.run_until_complete chain is fine (it wraps in a Task) but code executed via loop.call_soon callbacks, signal handlers, or low-level manual coroutine stepping has no current task; also entering a TaskGroup during interpreter/loop shutdown when the task context is already gone.","commonSituations":"Async generators asynchat-style finalized via loop.shutdown_asyncgens after their task died; driving coroutines manually with coro.send(None) in tests; exotic embedding of asyncio in another runtime; calling __aenter__ from a thread other than the loop thread.","solutions":["Ensure 'async with TaskGroup()' appears inside a coroutine that is scheduled as a Task (asyncio.run, loop.create_task, asyncio.create_task)","Move TaskGroup usage out of callbacks: wrap the whole workflow in one top-level coroutine task","For async generators needing structured concurrency, restructure so the group is entered and exited within a live task, not during aclose() from shutdown"],"exampleFix":"// before\nasync def worker():\n    async with asyncio.TaskGroup() as tg: ...\nloop.call_soon(lambda: asyncio.ensure_future(worker()))  # misdriven contexts can lack a current task\n\n// after\nasync def worker():\n    async with asyncio.TaskGroup() as tg: ...\nasyncio.run(worker())  # always runs inside a Task","handlingStrategy":"validation","validationCode":"null","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Enter TaskGroups only inside coroutines scheduled via asyncio.run/create_task","Never drive the entering code with manual send()/throw() or from loop callbacks","Keep structured concurrency out of async-generator finalization paths"],"tags":["asyncio","taskgroup","event-loop","api-misuse"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}