mutated × shared — the answer changes between runs
Hash-Seed Serialization Divergence
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.'
01the recipe
In the wild
compound ofImpure FunctionsCWE-758 Undefined BehaviorCache InvalidationcompoundCWE-340 Predictable IDs
example.py
# SMELL: a cache key built from set iteration order (randomized per process).
# (impure functions x cache invalidation)
def cache_key(tags):
return ",".join(str(t) for t in set(tags)) # set order varies per process
cache[cache_key(tags)] = render(tags) # key differs across workers
# -> each worker writes/reads a different key; the shared cache never hits.
# RIGHT: impose a stable order so the key is a pure function of the inputs.
def cache_key(tags):
return ",".join(sorted(set(map(str, tags)))) # deterministic across runsPython (and Go map) iteration order depends on a per-process-randomized hash seed -- implementation-defined behavior (CWE-758). A key derived from that order diverges between workers, so the shared cache constantly misses in production yet 'works' in a single-process dev run. Sort before joining to make the key a pure function of the inputs.
// observed
unsorted: every worker derives a different key -> cache hit-rate ~0 in prod sorted: one stable key across all processes -> the cache actually hits
02weakness catalog
Mapped weaknesses (CWE)
On its own, this defect is catalogued by MITRE as one or more of these weaknesses. The exploitable vulnerability usually appears only when it chains or combines with another.