{"record":{"id":"06e793ff2de8c958","repo":"temporalio/temporal","slug":"found-overlapping-iterators-in-iterator-list-left","errorCode":null,"errorMessage":"Found overlapping iterators in iterator list, left range: %v, right range: %v","messagePattern":"Found overlapping iterators in iterator list, left range: (.+?), right range: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/history/queues/slice.go","lineNumber":509,"sourceCode":"\tif s.scope.IsEmpty() {\n\t\ts.destroy()\n\t\treturn mergedSlices\n\t}\n\n\treturn append(mergedSlices, s)\n}\n\nfunc validateIteratorsOrderedDisjoint(\n\titerators []Iterator,\n) {\n\tif len(iterators) <= 1 {\n\t\treturn\n\t}\n\n\tfor idx, iterator := range iterators[:len(iterators)-1] {\n\t\tnextIterator := iterators[idx+1]\n\t\tif iterator.Range().ExclusiveMax.CompareTo(nextIterator.Range().InclusiveMin) >= 0 {\n\t\t\tpanic(fmt.Sprintf(\n\t\t\t\t\"Found overlapping iterators in iterator list, left range: %v, right range: %v\",\n\t\t\t\titerator.Range(),\n\t\t\t\tnextIterator.Range(),\n\t\t\t))\n\t\t}\n\t}\n}\n","sourceCodeStart":491,"sourceCodeEnd":517,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/history/queues/slice.go#L491-L517","documentation":"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.","triggerScenarios":"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.","commonSituations":"Only inside temporal-server history queue internals; appears after changes to split logic, upgrade mixing versions, or custom iterator implementations in forks.","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"],"exampleFix":"// before: appending split iterators unordered\niterators := append(leftIterators, rightIterators...)\n// after: sort by range min before merging\nsort.Slice(iterators, func(i, j int) bool {\n  return iterators[i].Range().InclusiveMin.CompareTo(iterators[j].Range().InclusiveMin) < 0\n})","handlingStrategy":"validation","validationCode":"// Pre-check before merging custom iterator lists:\nfor i := 0; i < len(iterators)-1; i++ {\n  if iterators[i].Range().ExclusiveMax.CompareTo(iterators[i+1].Range().InclusiveMin) >= 0 {\n    return fmt.Errorf(\"iterators %d and %d overlap\", i, i+1)\n  }\n}","typeGuard":null,"tryCatchPattern":"func safeMerge(iterators []queues.Iterator) (it queues.Iterator, err error) {\n  defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"iterator merge panic: %v\", r) } }()\n  return queues.MergeIterators(iterators), nil\n}","preventionTips":["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"],"tags":["go","history-service","task-queue","iterator-invariant"],"backgroundTag":"overlapping-iterator-ranges","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}