Report #10318
[gotcha] decimal context mutation leaks between asyncio tasks causing precision races
Use localcontext\(\) as an async context manager \(Python 3.11\+ decimal supports async context protocol\) or explicitly copy the context at task entry/exit. Better: pass Context explicitly to quantize\(\) etc., rather than relying on the implicit thread-local context. Never mutate getcontext\(\).prec in async code.
Journey Context:
The decimal module uses a thread-local context \(since PEP 327\). In threaded code, each thread has independent precision. However, asyncio runs all coroutines in a single thread. Therefore, when one coroutine changes getcontext\(\).prec or rounding mode, it immediately affects every other concurrent task. This causes non-deterministic precision bugs in financial calculations that appear only under specific interleavings. The solution is to never mutate the global context in async code; instead use decimal.localcontext\(\) to create a temporary context \(which works because it's a context manager that saves/restores state on enter/exit\). In Python 3.11\+, decimal contexts use contextvars to ensure they work properly with asyncio tasks automatically.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T10:19:23.719126+00:00— report_created — created