Report #53801
[gotcha] Catching CancelledError in asyncio does not prevent task cancellation from propagating
Never catch CancelledError unless you are immediately re-raising it or truly intend to suppress the cancellation \(rare\). Use try/finally for cleanup, and let CancelledError propagate. If you must catch it for cleanup, always re-raise it. To protect a coroutine from external cancellation while it finishes critical work, use asyncio.shield\(\), not try/except.
Journey Context:
Developers assume catching an exception neutralizes it. When they see CancelledError, they catch it to perform cleanup, but then the code continues. However, asyncio task cancellation is a state, not just an exception. When a task is cancelled, the CancelledError is injected at the current await point. Catching it only swallows that particular exception instance; the task remains in a 'cancelling' state and will raise CancelledError again at the next await. This creates infinite loops or delayed crashes. The only correct ways are: 1\) don't catch it, 2\) catch and immediately re-raise, or 3\) use shield to prevent the cancellation request from reaching the coroutine entirely.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T20:47:55.131772+00:00— report_created — created