{"record":{"id":"dd21736f0b3c567e","repo":"python/cpython","slug":"asynchronous-generator-ignored-generatorexit","errorCode":null,"errorMessage":"asynchronous generator ignored GeneratorExit","messagePattern":"asynchronous generator ignored GeneratorExit","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"Lib/_collections_abc.py","lineNumber":269,"sourceCode":"        Return next yielded value or raise StopAsyncIteration.\n        \"\"\"\n        if val is None:\n            if tb is None:\n                raise typ\n            val = typ()\n        if tb is not None:\n            val = val.with_traceback(tb)\n        raise val\n\n    async def aclose(self):\n        \"\"\"Raise GeneratorExit inside coroutine.\n        \"\"\"\n        try:\n            await self.athrow(GeneratorExit)\n        except (GeneratorExit, StopAsyncIteration):\n            pass\n        else:\n            raise RuntimeError(\"asynchronous generator ignored GeneratorExit\")\n\n    @classmethod\n    def __subclasshook__(cls, C):\n        if cls is AsyncGenerator:\n            return _check_methods(C, '__aiter__', '__anext__',\n                                  'asend', 'athrow', 'aclose')\n        return NotImplemented\n\n\nAsyncGenerator.register(async_generator)\n\n\nclass Iterable(metaclass=ABCMeta):\n\n    __slots__ = ()\n\n    @abstractmethod\n    def __iter__(self):","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_collections_abc.py#L251-L287","documentation":"Raised by collections.abc.AsyncGenerator.aclose() (Lib/_collections_abc.py) when athrow(GeneratorExit) does not terminate the asynchronous generator with GeneratorExit or StopAsyncIteration. An async generator must not yield another value after receiving GeneratorExit; doing so is a protocol violation reported as this RuntimeError.","triggerScenarios":"An async generator's except/finally path catches GeneratorExit (or BaseException) and executes another 'yield' before finishing; calling aclose() explicitly, letting asyncio's shutdown_asyncgens hook close it, or 'async for' early exit followed by aclose() triggers the path.","commonSituations":"Cleanup code in an async generator's finally block that awaits-and-yields (e.g. yielding progress updates during shutdown); overly broad exception handlers inside async generators; asyncio apps seeing the error during loop.close() when async generators are finalized.","solutions":["Remove every yield/asend suspension from the GeneratorExit/finally path; perform cleanup with plain awaits (asyncio.sleep-free) only.","Re-raise GeneratorExit after cleanup in the except block instead of falling through to more yields.","Replace 'except BaseException' with specific exception types so GeneratorExit is not swallowed.","Restructure so the generator signals cleanup completion via a queue/callback instead of yielding during teardown."],"exampleFix":"# before\nasync def agen():\n    try:\n        while True:\n            yield await produce()\n    finally:\n        yield 'closed'  # RuntimeError: asynchronous generator ignored GeneratorExit\n\n# after\nasync def agen():\n    try:\n        while True:\n            yield await produce()\n    finally:\n        await flush()  # await only, never yield","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    await agen.aclose()\nexcept RuntimeError as e:\n    if 'asynchronous generator ignored GeneratorExit' in str(e):\n        log.warning('async generator %r yielded during aclose', agen)\n    else:\n        raise","preventionTips":["No yield statements in finally blocks of async generators.","Catch GeneratorExit explicitly and re-raise after cleanup.","Close async generators explicitly (aclose()) before loop shutdown so failures surface during tests, not shutdown."],"tags":["asyncio","async-generator","generator-exit","collections-abc"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}