temporalio/temporal · error

Unable to merge scope with range %v with range %v by predica

Error message

Unable to merge scope with range %v with range %v by predicate

What it means

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.

Source

Thrown at service/history/queues/scope.go:90

) Scope {
	if !s.CanMergeByRange(incomingScope) {
		panic(fmt.Sprintf("Unable to merge scope with range %v with range %v by range", s.Range, incomingScope.Range))
	}

	return NewScope(s.Range.Merge(incomingScope.Range), s.Predicate)
}

func (s *Scope) CanMergeByPredicate(
	incomingScope Scope,
) bool {
	return s.Range.Equals(incomingScope.Range)
}

func (s *Scope) MergeByPredicate(
	incomingScope Scope,
) Scope {
	if !s.CanMergeByPredicate(incomingScope) {
		panic(fmt.Sprintf("Unable to merge scope with range %v with range %v by predicate", s.Range, incomingScope.Range))
	}

	return NewScope(s.Range, tasks.OrPredicates(s.Predicate, incomingScope.Predicate))
}

func (s *Scope) IsEmpty() bool {
	if s.Range.IsEmpty() {
		return true
	}

	if _, ok := s.Predicate.(*predicates.EmptyImpl[tasks.Task]); ok {
		return true
	}

	return false
}

func (s *Scope) Equals(scope Scope) bool {

View on GitHub (pinned to bde624efd1)

Solutions

  1. Check s.CanMergeByPredicate(incoming) first and only merge when ranges are equal
  2. If ranges are contiguous with equal predicates, use MergeByRange instead
  3. Re-align ranges (split both to the common range) before predicate merging

Example fix

// before
merged := s.MergeByPredicate(incoming) // panics if ranges differ

// after
var merged Scope
if s.CanMergeByPredicate(incoming) {
  merged = s.MergeByPredicate(incoming)
} else {
  merged = s
}
Defensive patterns

Strategy: validation

Validate before calling

if s.CanMergeByPredicate(incoming) {
  merged = s.MergeByPredicate(incoming)
}

Prevention

When it happens

Trigger: 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.

Common situations: Compaction loops merging scopes that were independently shrunk; asymmetric range updates after partial task completion; mixing scopes loaded from persistence at different times.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/bd7a5ade17a70d91. Report an issue: GitHub.