Report #6174
[gotcha] asyncio.gather with return\_exceptions=True silently swallowing CancelledError
Do not use return\_exceptions=True if you need to respect cancellation; instead, handle exceptions manually in wrapped coroutines, or check if the returned 'exception' is an instance of CancelledError and re-raise it to propagate cancellation properly.
Journey Context:
Structured concurrency dictates that when a task is cancelled, CancelledError should propagate up to cancel parent scopes. \`asyncio.gather\` with \`return\_exceptions=True\` catches \*all\* exceptions, including BaseException subclasses like CancelledError, and returns them as values in the result list. This effectively swallows cancellation signals. If the calling code expects to be cancellable, it will instead receive a CancelledError object as a 'successful' result, leading to silent failures or infinite loops. The fix is to avoid return\_exceptions=True in cancellable contexts, or to explicitly check \`if isinstance\(result, asyncio.CancelledError\): raise result\` to re-raise the cancellation.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-15T23:18:14.485032+00:00— report_created — created