Report #9931
[gotcha] asyncio task sees stale contextvars modified after create\_task but before execution
Snapshot contextvars immediately before calling create\_task\(\), or ensure no context modification occurs between task creation and await. For dynamic context updates, pass values explicitly as function arguments rather than relying on contextvars for task-local state that changes frequently between task scheduling and execution.
Journey Context:
Developers familiar with thread-local storage expect contextvars to behave like 'task-local storage' that is evaluated when the task begins executing. However, PEP 567 specifies that asyncio.Tasks capture the current context at instantiation time \(when create\_task\(\) is called\), not when the coroutine actually starts running on the event loop. This creates a temporal disconnect: if you modify a contextvar after calling create\_task\(\) but before the event loop processes that task \(e.g., during synchronous cleanup code or in a different task\), the new task will see the old value. This is particularly insidious in web frameworks where middleware might modify contextvars, and then an async task is created - if the middleware modifies the var again before the response completes, the background task has the stale value. The root cause is conflating 'task creation' with 'task execution start'.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T09:23:37.871375+00:00— report_created — created