Report #14577
[gotcha] asyncio.gather with return\_exceptions=True leaks tasks on cancellation
Do not use asyncio.gather if the caller may be cancelled \(e.g., with timeout\). Use asyncio.TaskGroup \(Python 3.11\+\) which properly propagates cancellation to child tasks, or manually track tasks and cancel them in a finally block.
Journey Context:
gather\(return\_exceptions=True\) is used to collect all results without stopping on first error. However, if the outer scope cancels the gather \(e.g., asyncio.wait\_for or asyncio.timeout\), the gather raises CancelledError but does NOT cancel the underlying tasks—they continue running as 'zombie' background tasks. This causes resource leaks and data races. TaskGroup was introduced specifically to handle structured concurrency: when the parent scope is cancelled, all child tasks are cancelled before the exception propagates.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T21:52:43.231396+00:00— report_created — created