{"record":{"id":"4d0d8e621f3be769","repo":"temporalio/temporal","slug":"unable-to-split-queue-slice-with-range-v-at-v","errorCode":null,"errorMessage":"Unable to split queue slice with range %v at %v","messagePattern":"Unable to split queue slice with range (.+?) at (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/history/queues/slice.go","lineNumber":103,"sourceCode":"\t\tmetricsHandler:     metricsHandler,\n\t}\n\ts.ensurePredicateSizeLimit()\n\treturn s\n}\n\nfunc (s *SliceImpl) Scope() Scope {\n\ts.stateSanityCheck()\n\treturn s.scope\n}\n\nfunc (s *SliceImpl) CanSplitByRange(key tasks.Key) bool {\n\ts.stateSanityCheck()\n\treturn s.scope.CanSplitByRange(key)\n}\n\nfunc (s *SliceImpl) SplitByRange(key tasks.Key) (left Slice, right Slice) {\n\tif !s.CanSplitByRange(key) {\n\t\tpanic(fmt.Sprintf(\"Unable to split queue slice with range %v at %v\", s.scope.Range, key))\n\t}\n\n\treturn s.splitByRange(key)\n}\n\nfunc (s *SliceImpl) splitByRange(key tasks.Key) (left *SliceImpl, right *SliceImpl) {\n\n\tleftScope, rightScope := s.scope.SplitByRange(key)\n\tleftTaskTracker, rightTaskTracker := s.split(leftScope, rightScope)\n\n\tleftIterators := make([]Iterator, 0, len(s.iterators)/2)\n\trightIterators := make([]Iterator, 0, len(s.iterators)/2)\n\tfor _, iter := range s.iterators {\n\t\titerRange := iter.Range()\n\t\tif leftScope.Range.ContainsRange(iterRange) {\n\t\t\tleftIterators = append(leftIterators, iter)\n\t\t\tcontinue\n\t\t}","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/history/queues/slice.go#L85-L121","documentation":"SliceImpl.SplitByRange panics when CanSplitByRange(key) is false, i.e. the split key is not strictly inside the slice's scope range. Splitting a slice divides its task trackers and iterators into two halves; a key outside the range would produce empty or invalid halves.","triggerScenarios":"Calling slice.SplitByRange(key) where key <= scope.Range.InclusiveMin or key >= scope.Range.ExclusiveMax; splitting an already-cleared or empty slice; using a key derived from a different slice's range.","commonSituations":"Queue load balancing choosing split points from stale metadata; splitting a slice that was already fully consumed; key comparison mistakes between inclusive/exclusive bounds.","solutions":["Call slice.CanSplitByRange(key) first and handle the false case without splitting","Choose the split key strictly within the slice's current scope range (e.g. midpoint)","Re-read the slice's Scope() before splitting rather than caching an old range"],"exampleFix":"// before\nleft, right := slice.SplitByRange(key) // panics if key outside range\n\n// after\nif slice.CanSplitByRange(key) {\n  left, right = slice.SplitByRange(key)\n}","handlingStrategy":"validation","validationCode":"if slice.CanSplitByRange(key) {\n  left, right = slice.SplitByRange(key)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always call CanSplitByRange first","Derive split keys from the slice's current Scope(), not cached ranges","Handle already-consumed slices without splitting"],"tags":["go","history-service","task-queue","range-split","panic"],"backgroundTag":"invalid-range-split-key","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}