Skip to content

asyncio.shutdown_asyncgens silently drops CancelledError from generator cleanup #150866

@deadlovelll

Description

@deadlovelll

Bug report

Bug description:

asyncio.BaseEventLoop.shutdown_asyncgens silently swallows CancelledError raised during asynchronous generator cleanup:

# Lib/asyncio/base_events.py:592-599
for result, agen in zip(results, closing_agens):
    if isinstance(result, Exception):
        self.call_exception_handler({
            'message': f'an error occurred during closing of '
                        f'asynchronous generator {agen!r}',
            'exception': result,
            'asyncgen': agen
        })

CancelledError that can be raised by the aclose() is not inherited from the Exception, it inherits from BaseException.

Reproducer:

import asyncio

async def agen():
    try:
        yield 1
    finally:
        raise asyncio.CancelledError("cancelled during cleanup")

caught = []

async def main():
    loop = asyncio.get_running_loop()
    loop.set_exception_handler(lambda loop, ctx: caught.append(ctx))
    g = agen()
    await g.__anext__()
    await loop.shutdown_asyncgens()

asyncio.run(main())
assert len(caught) == 1, f"Expected 1 handler call, got {len(caught)}"

Proposed fix:

Match both Exception and CancelledError

if isinstance(result, (Exception, asyncio.CancelledError)):

CPython versions tested on:

3.16, CPython main branch

Operating systems tested on:

macOS

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytopic-asynciotype-bugAn unexpected behavior, bug, or error
    No fields configured for issues without a type.

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions