Report #104549
[gotcha] asyncio.shield does not fully prevent cancellation of the outer task; the task is cancelled after the shielded coroutine completes
Use asyncio.shield only to protect a specific coroutine from being cancelled, not to prevent the enclosing task from being cancelled. If you need a task to be uncancellable, restructure your code so that the cancellation is handled at a higher level, or use asyncio.Task.cancel\(\) with careful checking. To ignore cancellation entirely, catch CancelledError and re-raise only after cleanup, but be aware that the task will still be marked cancelled.
Journey Context:
The shield context manager prevents cancellation from propagating into the enclosed coroutine, but the outer coroutine \(the one containing shield\) remains cancellable. When the outer task is cancelled while inside shield, the shielded coroutine continues to run, but as soon as it completes \(or raises\), the outer coroutine receives the CancelledError. This surprises developers who expect shield to make the entire task immune to cancellation. The Python docs explain: 'If the coroutine containing the shield is cancelled, the shielded coroutine continues to run, but the coroutine that called shield is cancelled after the shielded coroutine completes.' This is by design to allow graceful shutdown without blocking indefinitely.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-09-06T20:04:06.134913+00:00— report_created — created