temporalio/temporal · error
Found overlapping iterators in iterator list, left range
Error message
Found overlapping iterators in iterator list, left range: %v, right range: %v
What it means
validateIteratorsOrderedDisjoint checks a list of task iterators is sorted and non-overlapping before they are merged by mergeIterators. Each iterator covers a [min, max) key range; if an iterator's ExclusiveMax is >= the next iterator's InclusiveMin the ranges overlap and processing would visit keys twice, so the code panics. This is an internal invariant protecting the merge of split iterators.
Solutions
- Ensure iterators passed to mergeIterators are sorted ascending by InclusiveMin with disjoint ranges
- Fix range math in the code producing the iterators (SplitByRange must produce strictly ordered disjoint sub-ranges)
- Validate custom Iterator.Range() implementations match actual yielded keys
- Report to temporalio/temporal with both printed ranges if this occurs on an unmodified build
Example fix
// before: appending split iterators unordered
iterators := append(leftIterators, rightIterators...)
// after: sort by range min before merging
sort.Slice(iterators, func(i, j int) bool {
return iterators[i].Range().InclusiveMin.CompareTo(iterators[j].Range().InclusiveMin) < 0
}) Defensive patterns
Strategy: validation
Validate before calling
// Pre-check before merging custom iterator lists:
for i := 0; i < len(iterators)-1; i++ {
if iterators[i].Range().ExclusiveMax.CompareTo(iterators[i+1].Range().InclusiveMin) >= 0 {
return fmt.Errorf("iterators %d and %d overlap", i, i+1)
}
} Try / catch
func safeMerge(iterators []queues.Iterator) (it queues.Iterator, err error) {
defer func() { if r := recover(); r != nil { err = fmt.Errorf("iterator merge panic: %v", r) } }()
return queues.MergeIterators(iterators), nil
} Prevention
- Sort iterators ascending by InclusiveMin before merging
- Ensure split logic produces strictly ordered disjoint sub-ranges
- Keep custom Iterator.Range() consistent with the keys actually yielded
When it happens
Trigger: mergeIterators called with iterators assembled out of order or whose ranges overlap — e.g. after a bug in SplitByRange/SplitByPredicate range math, or a custom tasks.Iterator whose Range() disagrees with the keys it actually yields.
Common situations: Only inside temporal-server history queue internals; appears after changes to split logic, upgrade mixing versions, or custom iterator implementations in forks.
Related errors
- Can not append slice to existing list of slices, incoming…
- Can not invoke method on destroyed queue slice
- Found overlapping incoming slices, left slice range
- Queue slice encountered task doesn't belong to either…
- Queue slice get task from iterator doesn't belong to its…
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/06e793ff2de8c958.
Report an issue: GitHub.
Appendix: source
Thrown at service/history/queues/slice.go:509
if s.scope.IsEmpty() {
s.destroy()
return mergedSlices
}
return append(mergedSlices, s)
}
func validateIteratorsOrderedDisjoint(
iterators []Iterator,
) {
if len(iterators) <= 1 {
return
}
for idx, iterator := range iterators[:len(iterators)-1] {
nextIterator := iterators[idx+1]
if iterator.Range().ExclusiveMax.CompareTo(nextIterator.Range().InclusiveMin) >= 0 {
panic(fmt.Sprintf(
"Found overlapping iterators in iterator list, left range: %v, right range: %v",
iterator.Range(),
nextIterator.Range(),
))
}
}
}
View on GitHub (pinned to bde624efd1)