Report #87643
[gotcha] asyncio.wait\_for cancels the wrapped task on timeout even if the task already completed, losing the result
Catch \`asyncio.CancelledError\` from \`wait\_for\` and check \`task.done\(\)\` to retrieve the result that was computed during the race window. Better: avoid \`wait\_for\` for critical one-shot tasks; use manual timeout logic with \`asyncio.shield\(\)\` and explicit cancellation checking, or architect for idempotency since the task may have completed despite the timeout exception.
Journey Context:
\`wait\_for\` schedules a separate timeout task that cancels the user task when fired. If the user task completes exactly when the timeout fires, a race occurs: the completion and cancellation cross. CPython prioritizes the cancellation, raising \`CancelledError\` even though the task succeeded and the result is available internally. Developers often assume \`CancelledError\` means the task was actually cancelled and did not run to completion, leading to dangerous double-execution or data loss. \`shield\(\)\` does not prevent this race because the shield protects against external cancellation, not \`wait\_for\`'s internal cancellation logic. The only robust pattern is to catch \`CancelledError\`, check \`task.done\(\)\`, and extract \`task.result\(\)\`, accepting that timeout means 'result unknown' rather than 'task cancelled'.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T05:41:39.578825+00:00— report_created — created