python/cpython · error · RuntimeError
coroutine ignored GeneratorExit
Error message
coroutine ignored GeneratorExit
What it means
Raised by collections.abc.Coroutine.close() (Lib/_collections_abc.py) when throwing GeneratorExit into a coroutine does not end it with GeneratorExit or StopIteration. Per PEP 342/492, a coroutine must not catch GeneratorExit and continue suspending; if it yields or returns a value while being closed, the machinery reports this RuntimeError.
Source
Thrown at Lib/_collections_abc.py:183
Return next yielded value or raise StopIteration.
"""
if val is None:
if tb is None:
raise typ
val = typ()
if tb is not None:
val = val.with_traceback(tb)
raise val
def close(self):
"""Raise GeneratorExit inside coroutine.
"""
try:
self.throw(GeneratorExit)
except (GeneratorExit, StopIteration):
pass
else:
raise RuntimeError("coroutine ignored GeneratorExit")
@classmethod
def __subclasshook__(cls, C):
if cls is Coroutine:
return _check_methods(C, '__await__', 'send', 'throw', 'close')
return NotImplemented
Coroutine.register(coroutine)
class AsyncIterable(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __aiter__(self):
return AsyncIterator()View on GitHub (pinned to bc6749cc3b)
Solutions
- In the coroutine body, catch GeneratorExit only to run cleanup, then re-raise it (bare 'raise') or return without suspending again.
- Never yield/await again after GeneratorExit is delivered; move post-cleanup suspension out of the finally path.
- Narrow existing 'except BaseException' handlers inside the coroutine to specific exceptions where possible.
- For custom Coroutine subclasses, ensure throw() propagates GeneratorExit/StopIteration rather than returning normally.
Example fix
# before
async def __await__body():
try:
yield
except BaseException:
yield 'cleanup-done' # suspends again -> RuntimeError on close()
# after
async def __await__body():
try:
yield
except GeneratorExit:
await_cancelled_cleanup() # no further yield
raise Defensive patterns
Strategy: try-catch
Try / catch
try:
coro.close()
except RuntimeError as e:
if 'coroutine ignored GeneratorExit' in str(e):
log.warning('misbehaving coroutine swallowed GeneratorExit: %r', coro)
else:
raise Prevention
- Never yield/await after catching GeneratorExit; re-raise it after cleanup.
- Avoid 'except BaseException'/'except:' inside coroutine bodies.
- Add an explicit close() path instead of relying on GC finalization.
When it happens
Trigger: A coroutine's __await__/generator body wraps the suspension point in try/except that swallows GeneratorExit and yields again, or a custom class registered as Coroutine implements throw/send so that throw(GeneratorExit) resumes normally. Calling .close() (directly or via garbage collection / asyncio task cancellation teardown) then triggers it.
Common situations: Custom coroutine-like classes implementing __await__ with cleanup that catches BaseException too broadly; asyncio wrappers where a shielded await intercepts GeneratorExit; debugging why GC emits 'coroutine ignored GeneratorExit' during interpreter shutdown.
Related errors
- asynchronous generator ignored GeneratorExit
- Unknown thread safety level {level!r} for {name!r}. Valid le
- generator ignored GeneratorExit
- await wasn't used with future
- Passing coroutines is forbidden, use tasks explicitly.
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/c0891e8813b50434.
Report an issue: GitHub.