itertools.tee Silently Drops Items If You Reuse the Source (tested)
itertools.tee() looks like it makes two independent snapshots of an iterator. We measured what happens when you keep using the original iterator after splitting it, and it quietly removes items from both copies with no error at all.
1. Using the original iterator after tee() drops an item from both copies
import itertools
src = iter([1, 2, 3, 4, 5])
a, b = itertools.tee(src, 2)
print(next(src)) # pull one item from the ORIGINAL iterator
print(list(a))
print(list(b))
1
[2, 3, 4, 5]
[2, 3, 4, 5]
Measured: the 1 never shows up in either a or b -- both copies are missing the exact item that was pulled from src. There's no exception and no warning; the data is just gone from both tee'd iterators, not only the one you read from directly.
2. Never touching the original avoids the problem entirely
import itertools
src = iter(range(5))
a, b = itertools.tee(src, 2)
print(list(a)) # consume a fully first
print(list(b)) # b still has everything
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4]
Measured: as long as only the tee'd copies are read -- never the original src -- both a and b see every item, even when one is fully drained well before the other starts. tee() internally buffers items the faster consumer has already seen but the slower one hasn't, which is exactly why reaching around it to read src directly breaks that bookkeeping: the buffer never finds out an item was consumed.
3. Fix: treat the original iterator as unusable once tee() runs
import itertools
src = iter([1, 2, 3, 4, 5])
a, b = itertools.tee(src, 2)
del src # make it impossible to accidentally reuse
print(list(a))
print(list(b))
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
Measured: deleting the name (or simply never referencing it again) and reading only a and b gives both copies the full, correct sequence. The Python docs do note this requirement, but they don't describe it as silently dropping data -- in practice it reads as a hard-to-notice off-by-one, not a documented error case.
Frequently asked questions
Why is my itertools.tee copy missing an item?
We measured this: it happens when the original iterator passed to tee() is read directly after tee() runs. Every tee'd copy silently loses that item too, with no exception.
Does itertools.tee raise an error if I reuse the original iterator?
No -- we confirmed it fails silently. The item is simply missing from every tee'd copy's output, which is easy to miss if you're not comparing lengths.
How do I avoid the itertools.tee data-loss bug?
Stop referencing the original iterator entirely once you've passed it to tee() -- read only from the returned copies, even if one copy is read far ahead of the other.
Does it matter if the two tee'd iterators are read at different speeds?
No -- we measured one copy being fully consumed while the other hadn't started, and it still returned every item correctly. The bug is specifically about reusing the original source, not about uneven consumption speed between the copies.
Does this affect itertools.groupby the same way?
They're different bugs -- groupby's gotcha is about deferring list(group) until later, not about reusing a source iterator. See our separate groupby guide for that one; both stem from itertools functions sharing iterator state in ways that aren't obvious from the output.
Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in itertools module: created an iterator, split it with itertools.tee() into two copies, then called next() on the original iterator afterward, and compared that against never touching the original once tee() ran. PlainHeaders is our extension; Python's itertools module is built in.