{"record":{"id":"8b2459ba0917afaa","repo":"python/cpython","slug":"taskgroup-self-r-has-not-been-entered","errorCode":null,"errorMessage":"TaskGroup {self!r} has not been entered","messagePattern":"TaskGroup (.+?) has not been entered","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/taskgroups.py","lineNumber":220,"sourceCode":"                    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\")\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","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/taskgroups.py#L202-L238","documentation":"RuntimeError raised by TaskGroup.create_task() when called before __aenter__ has run (_entered is false). Until the group is entered it has no parent task or lifecycle to attach the new task to, so the passed coroutine is closed (to avoid a 'never awaited' warning) and the error is raised.","triggerScenarios":"tg = asyncio.TaskGroup(); tg.create_task(coro) without an enclosing 'async with tg:'; exposing create_task in a class method while the group is entered elsewhere/later; storing tasks at __init__ time before the context starts.","commonSituations":"Pre-registering startup work on a group before entering it; copy-pasting code from inside the block to outside; mixing up TaskGroup with the raw loop.create_task API where no entering is needed.","solutions":["Move every create_task call inside the 'async with asyncio.TaskGroup() as tg:' block","If you must accept work before entering, buffer coroutines in a list and spawn them right after __aenter__","Note the coroutine passed is closed by the failed call — build fresh coroutines when retrying"],"exampleFix":"// before\ntg = asyncio.TaskGroup()\ntg.create_task(poll())          # RuntimeError\nasync with tg: ...\n\n// after\nasync with asyncio.TaskGroup() as tg:\n    tg.create_task(poll())","handlingStrategy":"validation","validationCode":"null","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Keep every tg.create_task lexically inside the 'async with TaskGroup()' block","Buffer pre-arrival work in a list and spawn it right after entering the group","Note the failed call closes the coroutine — always build a fresh one on retry"],"tags":["asyncio","taskgroup","api-misuse","structured-concurrency"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}