Report #104723
[gotcha] Accidentally catching \`asyncio.CancelledError\` in a bare \`except Exception\` block suppresses cancellation, causing tasks to never cancel
Never use bare \`except Exception\` in asyncio code that may be cancelled. Either re-raise \`CancelledError\` explicitly, or use \`except \(SomeException, asyncio.CancelledError\)\` and handle cancellation separately. Alternatively, use \`asyncio.shield\(\)\` to protect critical sections from cancellation.
Journey Context:
\`asyncio.CancelledError\` is a subclass of \`BaseException\`, not \`Exception\`. This means a bare \`except Exception\` will not catch it – but many developers use \`except Exception\` thinking it covers everything. However, some libraries or code may accidentally catch \`BaseException\` \(e.g., \`except BaseException\` or \`except:\`\), which will swallow \`CancelledError\`. If that happens, the coroutine never actually cancels, and the task remains running silently. The asyncio documentation warns that \`CancelledError\` must be re-raised to allow cancellation to propagate. The design choice to make \`CancelledError\` inherit from \`BaseException\` is deliberate, mirroring \`KeyboardInterrupt\` and \`SystemExit\`, to prevent accidental suppression. The fix is to always be explicit about what exceptions you catch in async code.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-10-04T20:04:05.813291+00:00— report_created — created