mutated × shared — the answer changes between runs

Concurrent Modification During Iteration

One actor mutates a shared collection while another walks it — the loop sometimes throws, sometimes silently skips.

01the recipe

In the wild

example.py
# SMELL: iterate a shared collection while another thread mutates it.
# (for-loop control flow x threading & mutexes)
for sid, s in sessions.items():      # another thread runs sessions.pop(...)
    if s.expired:
        reap(sid)                    # -> RuntimeError, or entries silently skipped

# RIGHT: iterate a snapshot; mutate the original under a lock.
for sid, s in list(sessions.items()):    # stable copy to walk
    if s.expired:
        with lock:
            sessions.pop(sid, None)
Reading and writing one collection from two actors with no lock makes the iterator's behavior depend on timing: sometimes it raises, sometimes it skips or double-visits entries. The failure mode changes run to run.
// observed
race:  RuntimeError: dictionary changed size during iteration (sometimes)
right: snapshot iterated; mutation serialized, no surprise
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.