mutated × shared — the answer changes between runs
Nondeterminism
When an entropy source from mutated state meets an observation gap from shared state, the outcome depends on interleaving, not logic. The hallmark: you cannot reproduce it on demand.
A value that varies, observed across actors without synchronization, lets timing pick the result instead of your code.
In the wild
Temporal Interleaving
The schedule, not the logic, picks the result.
The gap between checking a resource and using it is a window another actor can slip through — so the bug only fires when the interleaving lines up.
Incrementing shared state is three steps — read, add, write — and without a lock two actors overwrite each other's result.
Two requests write one variable; whichever resolves last wins — and completion order isn't the order you asked in.
One actor mutates a shared collection while another walks it — the loop sometimes throws, sometimes silently skips.
Whether a request succeeds or stalls depends on how many others hold the pool right now -- so the same call passes alone and fails under load.
Observational Staleness
You act on a value that has already moved.
Caching a result that depends on hidden mutable state serves the old answer forever — nobody invalidated it.
A freed allocation is still reachable through a second name; the stale read returns whatever reused the slot.
A pooled connection carries un-reset state from a prior borrower, so your result depends on who held it before you.
A thread sees the singleton's reference published before its fields are -- so it reads a half-built object, but only on the rare interleaving.
You write to the primary, then read back from a replica that hasn't caught up -- so you act on a value that has already moved, but only when replication lag outruns your round-trip.
Entropic Divergence
A hidden random or identity source makes runs differ.
Deriving a 'unique' id from the clock works until two requests land in the same tick.
A predictable temp path plus a gap between checking and opening it is a window another actor can slip a symlink through -- so the write lands elsewhere only when the timing lines up.
One shared object with mutable per-call state, hit by many threads, lets one request's data bleed into another's.
A cache key built by iterating an unordered set differs each process, because the hash seed is randomized -- so the cache never hits and 'it works on my machine.'
Handlers auto-register via a decorator whose effective order depends on import/await timing -- so when two claim the same route, which one wins changes run to run.