python runtime_error ai_generated true

asyncio.exceptions.CancelledError: Task was destroyed but it is pending!

ID: python/asyncio-gather-cancelled-error

Also available as: JSON · Markdown · 中文
80%Fix Rate
85%Confidence
0Evidence
2024-03-15First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
3.8 active
3.9 active
3.10 active

Root Cause

When using asyncio.gather() with return_exceptions=False, if one task raises CancelledError (e.g., due to timeout), the gather is cancelled and other tasks are not properly awaited, leading to pending task destruction warnings.

generic

中文

使用 asyncio.gather() 且 return_exceptions=False 时,如果某个任务因超时等原因抛出 CancelledError,gather 被取消,其他任务未被正确等待,导致待处理任务销毁警告。

Workarounds

  1. 90% success
    results = await asyncio.gather(*tasks, return_exceptions=True)
    for r in results:
        if isinstance(r, asyncio.CancelledError):
            # handle cancellation gracefully
  2. 85% success
    done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
    for task in pending:
        task.cancel()
    await asyncio.gather(*pending, return_exceptions=True)

Dead Ends

Common approaches that don't work:

  1. 60% fail

    CancelledError is not always raised synchronously; it can be raised during await, and ignoring it may leave tasks in inconsistent states.

  2. 70% fail

    Shield only protects against cancellation of the outer task, not the inner tasks; it doesn't solve the root issue of pending tasks.