Report #53586
[gotcha] CancelledError returned as value by asyncio.gather with return\_exceptions=True
When using \`asyncio.gather\(\*tasks, return\_exceptions=True\)\`, explicitly check for \`asyncio.CancelledError\` in the returned results list; do not assume all exceptions in the list are "business logic" errors. To distinguish true cancellation from a task that merely raised CancelledError, compare the task's \`done\(\)\` state or track cancellation separately.
Journey Context:
With \`return\_exceptions=True\`, \`gather\(\)\` converts all exceptions \(including \`CancelledError\`\) into result values. This makes it impossible to distinguish between a task that was externally cancelled and a task that completed by raising \`CancelledError\` \(or a subclass\) as a normal exception. This breaks error handling code that expects \`CancelledError\` to always propagate or be distinguishable from value returns. The fix requires checking \`isinstance\(result, asyncio.CancelledError\)\` and re-raising or handling separately.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T20:26:33.515380+00:00— report_created — created