{"record":{"id":"ed49e230fca7e8df","repo":"temporalio/temporal","slug":"unable-to-merge-iterator-range-v-with-incoming-it","errorCode":null,"errorMessage":"Unable to merge iterator range %v with incoming iterator range %v","messagePattern":"Unable to merge iterator range (.+?) with incoming iterator range (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/history/queues/iterator.go","lineNumber":98,"sourceCode":"\tleftRange, rightRange := i.remainingRange.Split(key)\n\tleft = NewIterator(\n\t\ti.paginationFnProvider,\n\t\tleftRange,\n\t)\n\tright = NewIterator(\n\t\ti.paginationFnProvider,\n\t\trightRange,\n\t)\n\treturn left, right\n}\n\nfunc (i *IteratorImpl) CanMerge(iter Iterator) bool {\n\treturn i.remainingRange.CanMerge(iter.Range())\n}\n\nfunc (i *IteratorImpl) Merge(iter Iterator) Iterator {\n\tif !i.CanMerge(iter) {\n\t\tpanic(fmt.Sprintf(\"Unable to merge iterator range %v with incoming iterator range %v\", i.remainingRange, iter.Range()))\n\t}\n\n\treturn NewIterator(\n\t\ti.paginationFnProvider,\n\t\ti.remainingRange.Merge(iter.Range()),\n\t)\n}\n\nfunc (i *IteratorImpl) Remaining() Iterator {\n\treturn NewIterator(\n\t\ti.paginationFnProvider,\n\t\ti.remainingRange,\n\t)\n}\n","sourceCodeStart":80,"sourceCodeEnd":113,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/history/queues/iterator.go#L80-L113","documentation":"IteratorImpl.Merge panics when CanMerge(iter) is false, meaning the incoming iterator's range is not contiguous/adjacent to this iterator's remaining range. Ranges can only merge when their union is itself a valid continuous range.","triggerScenarios":"Calling Merge with an iterator whose range has a gap or overlaps non-adjacently with the receiver's range — often after queue rebalancing paired iterators that were not neighbors.","commonSituations":"Rebalancing logic that groups iterators by key order incorrectly; merging iterators after one was partially consumed so its Range() shrank; mismatched sources (different queue/task types) producing non-adjacent ranges.","solutions":["Check it.CanMerge(other) before calling Merge and skip or reorder otherwise","Sort candidate iterators by range before merging so only adjacent ranges are paired","Verify both iterators target the same queue/category and range universe","Don't merge an iterator that has already been consumed; use its original Range() for planning"],"exampleFix":"// before\nmerged := it.Merge(other)\n// after\nif it.CanMerge(other) {\n    merged = it.Merge(other)\n} else {\n    merged = it // keep separate\n}","handlingStrategy":"validation","validationCode":"if !it.CanMerge(other) {\n    // keep iterators separate or reorder candidates\n    return\n}\nmerged := it.Merge(other)","typeGuard":null,"tryCatchPattern":"func safeMerge(it queues.Iterator, other queues.Iterator) (merged queues.Iterator) {\n    defer func() {\n        if r := recover(); r != nil {\n            merged = it\n        }\n    }()\n    if !it.CanMerge(other) {\n        return it\n    }\n    return it.Merge(other)\n}","preventionTips":["Sort ranges by InclusiveMin before merging","Only merge iterators from the same queue and task category","Merge before consuming iterators, not after partial iteration","Add rebalancing tests that pair every iterator with its neighbor"],"tags":["go","panic","iterator","range-merge","history-service"],"backgroundTag":"non-adjacent-range-merge","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}