Desk Clarity

A field guide to everyday digital problems.

Developer tools / Practical guide

Python Dictionary Changed Size During Iteration: Choose a Snapshot or Rebuild

A dictionary cleanup raises RuntimeError after removing a key. Separate the traversal from structural changes.

By ON Lab2 min readSources checked November 10, 2026 (KST)

Adding or deleting keys while traversing a live dictionary view can invalidate the iteration. Build a new dictionary, or snapshot the keys before editing the original.

Check the failure with a small fixture

A dictionary cleanup raises RuntimeError after removing a key. Separate the traversal from structural changes.

settings = {"active": 4, "expired": 0, "pending": 0}
try:
    for name in settings:
        if settings[name] == 0:
            del settings[name]
except RuntimeError:
    print("live traversal invalidated")
source = {"active": 4, "expired": 0, "pending": 0}
alias = source
for name in list(source):
    if source[name] == 0:
        del source[name]
assert alias is source and source == {"active": 4}
rebuilt = {k: v for k, v in {"a": 0, "b": 3}.items() if v != 0}
assert rebuilt == {"b": 3}

What the result means

The failing loop may already have changed the dictionary before the exception. Rerun the corrected example from fresh data rather than treating the failed operation as a rollback. list(source) snapshots keys, so deleting a key no longer changes the sequence being traversed.

Choose the correction for your caller

Choose rebuilding when callers can accept a new mapping. Choose the key snapshot when other references must observe edits to the same mapping object. A list of items also freezes the key-value pairs for that pass, whereas a key snapshot still reads current values when you index the mapping. Updating an existing value is a different operation from adding or removing keys, but do not rely on complex mutation during traversal for portable algorithms.

Limits and the next check

This is not concurrency control. Other threads or callbacks can invalidate assumptions after the snapshot; coordinate ownership or use application-level locking. A snapshot is shallow and does not clone nested mutable values.

Related: Compare a related data or execution contract.

The embedded Python example was executed as an isolated local script on November 10, 2026 (KST), using Python 3.11.6. It demonstrates the stated boundary; it is not a test of your application or a promise of compatibility with every Python release.

Sources & further reading