{"record":{"id":"bd7a5ade17a70d91","repo":"temporalio/temporal","slug":"unable-to-merge-scope-with-range-v-with-range-v-bd7a5a","errorCode":null,"errorMessage":"Unable to merge scope with range %v with range %v by predicate","messagePattern":"Unable to merge scope with range (.+?) with range (.+?) by predicate","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/history/queues/scope.go","lineNumber":90,"sourceCode":") Scope {\n\tif !s.CanMergeByRange(incomingScope) {\n\t\tpanic(fmt.Sprintf(\"Unable to merge scope with range %v with range %v by range\", s.Range, incomingScope.Range))\n\t}\n\n\treturn NewScope(s.Range.Merge(incomingScope.Range), s.Predicate)\n}\n\nfunc (s *Scope) CanMergeByPredicate(\n\tincomingScope Scope,\n) bool {\n\treturn s.Range.Equals(incomingScope.Range)\n}\n\nfunc (s *Scope) MergeByPredicate(\n\tincomingScope Scope,\n) Scope {\n\tif !s.CanMergeByPredicate(incomingScope) {\n\t\tpanic(fmt.Sprintf(\"Unable to merge scope with range %v with range %v by predicate\", s.Range, incomingScope.Range))\n\t}\n\n\treturn NewScope(s.Range, tasks.OrPredicates(s.Predicate, incomingScope.Predicate))\n}\n\nfunc (s *Scope) IsEmpty() bool {\n\tif s.Range.IsEmpty() {\n\t\treturn true\n\t}\n\n\tif _, ok := s.Predicate.(*predicates.EmptyImpl[tasks.Task]); ok {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (s *Scope) Equals(scope Scope) bool {","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/history/queues/scope.go#L72-L108","documentation":"Scope.MergeByPredicate panics when the incoming scope's range differs from the receiver's range. Merging by predicate combines predicates with OR and is only valid when both scopes cover exactly the same key range. This prevents constructing a scope whose predicate-merged range semantics would be wrong.","triggerScenarios":"Calling s.MergeByPredicate(incoming) where incoming.Range != s.Range, typically after splitting a range at different keys or after one side was shrunk (tasks completed/shrunk) but the other wasn't.","commonSituations":"Compaction loops merging scopes that were independently shrunk; asymmetric range updates after partial task completion; mixing scopes loaded from persistence at different times.","solutions":["Check s.CanMergeByPredicate(incoming) first and only merge when ranges are equal","If ranges are contiguous with equal predicates, use MergeByRange instead","Re-align ranges (split both to the common range) before predicate merging"],"exampleFix":"// before\nmerged := s.MergeByPredicate(incoming) // panics if ranges differ\n\n// after\nvar merged Scope\nif s.CanMergeByPredicate(incoming) {\n  merged = s.MergeByPredicate(incoming)\n} else {\n  merged = s\n}","handlingStrategy":"validation","validationCode":"if s.CanMergeByPredicate(incoming) {\n  merged = s.MergeByPredicate(incoming)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Gate MergeByPredicate behind CanMergeByPredicate (ranges must be Equal)","Use MergeByRange when predicates match but ranges are contiguous","Re-align ranges after shrink operations before attempting predicate merges"],"tags":["go","history-service","task-queue","predicate-merge","panic"],"backgroundTag":"range-mismatch-merge","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}