[Edit: This bug was originally reported as "not thread safe", and updated to "not atomic"]
Bug report
Bug description:
In free-threaded mode, calling copy on collections.deque is not thread safe atomic and can raise RuntimeError: deque mutated during iteration errors.
Example code:
import sys import threading from collections import deque from copy import copy print(f"Python {sys.version}") print(f"GIL enabled: {sys._is_gil_enabled()}") d = deque(range(100)) stop = threading.Event() def mutate(): i = 0 while not stop.is_set(): d.append(i) if len(d) > 200: d.popleft() i += 1 def copy_loop(): while not stop.is_set(): copy(d) barrier = threading.Barrier(5) def run(fn): barrier.wait() fn() threads = [ threading.Thread(target=run, args=(f,), daemon=True) for f in [mutate, mutate, copy_loop, copy_loop] ] for t in threads: t.start() barrier.wait() stop.wait(timeout=5) stop.set() for t in threads: t.join(timeout=5) print("Done")
Running under free-threaded build:
❯ ./python /tmp/deque.py Python 3.15.0a6+ free-threading build (heads/main:945bf8ce1bf, Feb 13 2026, 22:04:08) [GCC 11.4.0] GIL enabled: False Exception in thread Thread-4 (run): Exception in thread Thread-3 (run): Traceback (most recent call last): Traceback (most recent call last): File "cpython/Lib/threading.py", line 1075, in _bootstrap_inner self._context.run(self.run) ~~~~~~~~~~~~~~~~~^^^^^^^^^^ File "cpython/Lib/threading.py", line 1017, in run self._target(*self._args, **self._kwargs) ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/tmp/deque.py", line 32, in run fn() ~~^^ File "/tmp/deque.py", line 24, in copy_loop copy(d) ~~~~^^^ File "cpython/Lib/copy.py", line 82, in copy return copier(x) RuntimeError: deque mutated during iteration File "cpython/Lib/threading.py", line 1075, in _bootstrap_inner self._context.run(self.run) ~~~~~~~~~~~~~~~~~^^^^^^^^^^ File "cpython/Lib/threading.py", line 1017, in run self._target(*self._args, **self._kwargs) ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/tmp/deque.py", line 32, in run fn() ~~^^ File "/tmp/deque.py", line 24, in copy_loop copy(d) ~~~~^^^ File "cpython/Lib/copy.py", line 82, in copy return copier(x) RuntimeError: deque mutated during iteration Done
CPython versions tested on:
CPython main branch, 3.14
Operating systems tested on:
Linux