{"record":{"id":"941abe8c130a5164","repo":"temporalio/temporal","slug":"queue-slice-encountered-task-doesn-t-belong-to-eit","errorCode":null,"errorMessage":"Queue slice encountered task doesn't belong to either scopes during split, scope: %v and %v, task: %v, task type: %v","messagePattern":"Queue slice encountered task doesn't belong to either scopes during split, scope: (.+?) and (.+?), task: (.+?), task type: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/history/queues/tracker.go","lineNumber":44,"sourceCode":"}\n\nfunc (t *executableTracker) split(\n\tthisScope Scope,\n\tthatScope Scope,\n) (*executableTracker, *executableTracker) {\n\tthat := executableTracker{\n\t\tpendingExecutables: make(map[tasks.Key]Executable, len(t.pendingExecutables)/2),\n\t\tgrouper:            t.grouper,\n\t\tpendingPerKey:      make(map[any]int, len(t.pendingPerKey)),\n\t}\n\n\tfor key, executable := range t.pendingExecutables {\n\t\tif thisScope.Contains(executable) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !thatScope.Contains(executable) {\n\t\t\tpanic(fmt.Sprintf(\"Queue slice encountered task doesn't belong to either scopes during split, scope: %v and %v, task: %v, task type: %v\",\n\t\t\t\tthisScope, thatScope, executable.GetTask(), executable.GetType()))\n\t\t}\n\n\t\tdelete(t.pendingExecutables, key)\n\t\tthat.pendingExecutables[key] = executable\n\n\t\tgroupKey := t.grouper.Key(executable)\n\t\tt.pendingPerKey[groupKey]--\n\t\tthat.pendingPerKey[groupKey]++\n\t}\n\n\treturn t, &that\n}\n\nfunc (t *executableTracker) merge(incomingTracker *executableTracker) *executableTracker {\n\tthisExecutables, thisPendingTasks := t.pendingExecutables, t.pendingPerKey\n\tthatExecutables, thatPendingTasks := incomingTracker.pendingExecutables, incomingTracker.pendingPerKey\n\tif len(thisExecutables) < len(thatExecutables) {","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/history/queues/tracker.go#L26-L62","documentation":"When an executableTracker splits, every pending executable must belong to exactly one of the two resulting scopes (thisScope or thatScope). This panic fires when a pending task falls into neither, meaning the split scopes have a gap or the task predates a scope change. It is an internal invariant protecting task ownership during queue splits.","triggerScenarios":"splitByRange or SplitByPredicate running while pendingExecutables contains a task outside both new scopes — e.g. scope shrunk (ShrinkScope) after tasks were loaded, or split ranges/predicate computed inconsistently with what was loaded earlier.","commonSituations":"Seen in temporal-server history service during aggressive queue splitting/merging under memory pressure; usually a bug in range or predicate computation, or a task added outside SelectTasks' range check; forked iterators or upgrade skew can also trigger it.","solutions":["Ensure scopes produced by a split exactly partition the original scope (no gaps)","Verify tasks cannot be added to the tracker after their slice's scope was shrunk","Check that executable.GetType()/GetTask() in the panic message to identify the producer, then trace why its key escaped both scopes","Report to temporalio/temporal with both scopes and the task details if reproducible"],"exampleFix":"// before: shrinking scope without clearing tasks loaded under the old scope\nslice.ShrinkScope() // pending executables may now fall outside both split scopes\n// after: clear or re-bucket pending tasks when narrowing the scope (as Clear does)\nslice.Clear()","handlingStrategy":"validation","validationCode":"// Before splitting, verify the two new scopes partition the old scope:\nif !oldScope.Range.Equal(newThisScope.Range.Union(newThatScope.Range)) {\n  return fmt.Errorf(\"split scopes do not cover original range\")\n}","typeGuard":null,"tryCatchPattern":"func safeSplit(t queues.ExecutableTracker, a, b queues.Scope) (err error) {\n  defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"split panic: %v\", r) } }()\n  t.Split(a, b)\n  return nil\n}","preventionTips":["Ensure split scopes exactly partition the original scope with no gaps","Clear or re-bucket pending tasks before shrinking a slice's scope","Avoid mutating scope while tasks are being loaded via SelectTasks"],"tags":["go","history-service","task-queue","split-invariant"],"backgroundTag":"queue-split-scope-mismatch","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}