Recursion how to avoid Python set changed set during iteration RuntimeError
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
RuntimeError: Set changed size during iteration means Python detected that the same set object was being mutated while an active iterator was walking it. Recursion makes this easier to trigger because the mutation may happen in a deeper stack frame while the outer frame still thinks it is safely iterating. The real fix is to separate iteration from mutation, not to ban recursion entirely.
Why Python Raises the Error
Sets are mutable hash tables. Their internal layout can change when items are inserted or removed, so Python does not allow the set to be structurally modified while an active iterator is walking it.
This simple example fails:
It raises a runtime error because the loop and the mutation target the same set at the same time.
The same rule applies in recursive code:
Even if the recursive call is the one doing the mutation, the outer frame is still iterating the same set object.
Safe Pattern 1: Iterate Over a Snapshot
The simplest fix is to iterate over a snapshot while mutating the original:
list(items) captures the elements at the start of the loop, so later mutations do not affect the iterator.
For recursion:
This works because each frame iterates over a list copy, not over the live set object being changed.
Safe Pattern 2: Build a New Set for the Recursive Call
Sometimes mutating in place is the wrong model entirely. If recursion conceptually operates on "remaining work," create a new set and pass that down:
This approach is often clearer because each recursive call gets its own independent view of the remaining items.
Safe Pattern 3: Collect Changes and Apply Them Later
If the loop is doing analysis and the mutation is just a final cleanup step, collect the changes first:
This is often the best option when the recursive logic depends on seeing the original collection consistently during one full pass.
When pop() Is Better Than Iteration
If the algorithm is really "consume one item until nothing remains," a while loop with pop() is often simpler than iterating and mutating in the same structure:
This works because there is no active iterator over the set. You are explicitly removing one element at a time.
If you still want recursion, combine pop() with a base case:
That pattern is safe because it does not iterate with for item in items.
Common Pitfalls
- Copying the set after iteration already began. Fix: create the snapshot before the
forloop starts. - Mutating the same set through a different variable reference. Fix: remember that object identity matters, not the variable name.
- Using recursion where an iterative consume loop is clearer. Fix: prefer
while items:pluspop()when the task is simple consumption. - Forgetting recursion depth limits. Fix: use iteration for large workloads where recursion could become deep.
- Mixing analysis and mutation in the same pass. Fix: collect changes first, then apply them afterward.
Summary
- The error happens when a set is mutated while an active iterator is using it.
- Recursive calls do not make that rule disappear; they often make it easier to violate.
- Safe fixes include iterating over a snapshot, passing a new set to recursive calls, or collecting changes for later.
- If you are consuming the set one item at a time,
pop()plus awhileloop or a recursive base case is often the cleanest pattern. - When in doubt, separate iteration from mutation.
Related reading
- Recursion or Iteration?
- Recursion Returning a list in order traversal
- recursion versus iteration
- Recursive-backtracking algorithm for solving the partitioning problem
- Recursive function to create hierarchical JSON object?
- recursive query for adjacency list to preorder tree traversal in SQL?
- Recursively iterate through all subdirectories using pathlib
- Redirect stdout to a file in Python?

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.