Report #24284
[gotcha] asyncio.gather masks original exception with CancelledError when other tasks raise
Use return\_exceptions=True in gather to prevent cancellation cascade, or use asyncio.TaskGroup \(Python 3.11\+\) which properly bundles exceptions in ExceptionGroup without masking the original cause
Journey Context:
When gather is called without return\_exceptions=True and one task raises an exception, gather immediately cancels all other pending tasks by injecting CancelledError into them. If any of those tasks were also in the process of raising an exception \(common in cleanup code or \_\_aexit\_\_ blocks\), the CancelledError propagates instead of the original exception, masking the root cause. This leads to debugging nightmares where logs show CancelledError but the actual bug \(e.g., AttributeError in a database connection teardown\) is lost. TaskGroup \(PEP 654\) solves this by collecting all exceptions into an ExceptionGroup, preserving the context of every failed task and preventing the cancellation race condition.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T19:10:20.972688+00:00— report_created — created