---
title: Do Not Modify Collection While Iterating Over It
impact: HIGH
impactDescription: Adding or removing items from a list, dict, or set while iterating over it causes RuntimeError, skipped elements, or undefined behavior depending on the collection type.
tags: python, iteration, bugs, pitfalls, quality
---

## Do Not Modify Collection While Iterating Over It

Modifying a `dict` or `set` while iterating raises `RuntimeError: dictionary changed size during iteration` / `set changed size during iteration`. Modifying a `list` during iteration does **not** raise an error but silently skips or processes elements multiple times, producing wrong results.

Always iterate over a copy, build a new collection, or collect modifications and apply them after the loop.

**Incorrect:**
```python
# dict — raises RuntimeError
config = {"debug": True, "deprecatedKey": "val", "timeout": 30}

for key in config:
    if key.startswith("deprecated"):
        del config[key]   # RuntimeError: dictionary changed size during iteration

# set — raises RuntimeError
seen = {1, 2, 3, 4, 5}

for item in seen:
    if item % 2 == 0:
        seen.discard(item)   # RuntimeError: set changed size during iteration

# list — silent bug: skips elements
items = [1, 2, 2, 3, 4]

for i, item in enumerate(items):
    if item == 2:
        items.remove(item)   # skips the second 2 silently
```

**Correct:**
```python
# dict — iterate over a copy of keys
config = {"debug": True, "deprecatedKey": "val", "timeout": 30}

for key in list(config.keys()):
    if key.startswith("deprecated"):
        del config[key]

# Or build a new dict with dict comprehension (preferred for clarity)
config = {k: v for k, v in config.items() if not k.startswith("deprecated")}

# set — iterate over a copy
seen = {1, 2, 3, 4, 5}
to_remove = {item for item in seen if item % 2 == 0}
seen -= to_remove

# list — collect removals, apply after loop
items = [1, 2, 2, 3, 4]
items = [item for item in items if item != 2]   # list comprehension

# Or for in-place modification, iterate in reverse
items = [1, 2, 2, 3, 4]
for i in range(len(items) - 1, -1, -1):
    if items[i] == 2:
        del items[i]
```

**Tools:** Ruff `E4702` (modified-iterating-dict), `E4703` (modified-iterating-set), `W4701` (modified-iterating-list), Pylint `modified_iteration` checker, flake8
