temporalio/temporal · error
Found overlapping iterators in iterator list, left range: %v
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.
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)
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 sl
- Found overlapping incoming slices, left slice range: %v, rig
- reader with ID %v already exists
- Unable to split scope with range %v at %v
- Unable to merge scope with range %v with range %v by range
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/06e793ff2de8c958.
Report an issue: GitHub.