BugHunt

RuntimeError: dictionary changed size during iteration

You added or removed keys from a dict while looping over it. Loop over a copy of the keys, or build a new dict.

PythonMutation and copying bugs

What it means

A dict iterator walks the internal table in order. Adding or removing keys can reorganise that table mid-walk, so Python refuses rather than silently skipping or repeating items. Sets raise the same error. Lists do not raise — they skip items instead, which is worse.

Common causes

1. Deleting entries while looping

Removing keys changes the size the iterator is tracking.

Breaks

for key in stock:
    if stock[key] == 0:
        del stock[key]

Works

stock = {k: v for k, v in stock.items() if v != 0}

2. Adding derived keys while looping

Adding a key during iteration is just as unsafe as removing one.

Breaks

for name in prices:
    prices[name + "_tax"] = prices[name] * 1.2

Works

for name in list(prices):
    prices[name + "_tax"] = prices[name] * 1.2

3. Mutating inside a function called from the loop

The loop looks innocent; the helper it calls removes the key.

Breaks

for user_id in sessions:
    expire_if_old(user_id)   # does del sessions[user_id]

Works

for user_id in list(sessions):
    expire_if_old(user_id)

How to find it in your own code

Iterate over list(d) or list(d.items()) — a snapshot — when you need to modify the dict in the loop. When you are filtering, a dict comprehension that builds a new dict is cleaner and has no ordering surprises.

Still not sure why yours breaks?

Paste it into the visualizer and watch it run line by line, with every variable at every step. Free, and it runs in your browser.

Other common errors