A ContextVar.set call returns a single-use token that restores the value it replaced in the current context.
Make this comfortable
Python ContextVar tokens: restore nested request state exactly
Observed contract
A receipt handler temporarily changes the request ID twice. Resetting the inner token exposes the outer ID; resetting the outer one restores the unbound default. The program also proves that reusing a token raises an error rather than applying an old value again.
Boundary
A token belongs to its variable and context. Do not hand it to another task for cleanup. Use try/finally around each temporary set, because an exception between set and reset otherwise leaves the current task with stale request data.
Executable case
from contextvars import ContextVar
request_id = ContextVar("request_id", default="unbound")
outer_token = request_id.set("R-47")
try:
inner_token = request_id.set("R-48")
try:
print("nested", request_id.get())
finally:
request_id.reset(inner_token)
print("outer", request_id.get())
finally:
request_id.reset(outer_token)
print("restored", request_id.get())
try:
request_id.reset(outer_token)
except RuntimeError:
print("second_reset_rejected", True)Output
nested R-48
outer R-47
restored unbound
second_reset_rejected TrueCost
Each set records a prior binding in a token. Copying the current context is cheap, but values retained by a long-lived context can keep large request objects alive; store a compact identifier instead.
Common Mistakes
- Reset tokens in reverse nesting order.
- A ContextVar value is context-local, not a process-wide request registry.
- A token cannot safely be used twice or reset in another context.
Connected lessons
python
contextvar-token-reset
