temporalio/temporal · error
Unable to split scope with range %v at %v
Error message
Unable to split scope with range %v at %v
What it means
Scope.SplitByRange panics when the requested split key is not strictly inside the scope's range (Range.CanSplit(key) is false). Splitting requires the key to fall strictly between InclusiveMin and ExclusiveMax so both halves are non-empty. This guards against producing degenerate empty scopes.
Source
Thrown at service/history/queues/scope.go:42
}
}
func (s *Scope) Contains(task tasks.Task) bool {
return s.Range.ContainsKey(task.GetKey()) &&
s.Predicate.Test(task)
}
func (s *Scope) CanSplitByRange(
key tasks.Key,
) bool {
return s.Range.CanSplit(key)
}
func (s *Scope) SplitByRange(
key tasks.Key,
) (left Scope, right Scope) {
if !s.CanSplitByRange(key) {
panic(fmt.Sprintf("Unable to split scope with range %v at %v", s.Range, key))
}
leftRange, rightRange := s.Range.Split(key)
return NewScope(leftRange, s.Predicate), NewScope(rightRange, s.Predicate)
}
func (s *Scope) SplitByPredicate(
predicate tasks.Predicate,
) (pass Scope, fail Scope) {
passScope := NewScope(
s.Range,
tasks.AndPredicates(s.Predicate, predicate),
)
failScope := NewScope(
s.Range,
tasks.AndPredicates(s.Predicate, predicates.Not(predicate)),
)
return passScope, failScopeView on GitHub (pinned to bde624efd1)
Solutions
- Call scope.CanSplitByRange(key) first and only split when it returns true
- Clamp/choose the split key strictly inside (InclusiveMin, ExclusiveMax), e.g. a midpoint of the range
- Handle empty or un-splittable scopes by returning them unchanged instead of splitting
Example fix
// before
left, right := scope.SplitByRange(key) // panics if key outside range
// after
var left, right Scope
if scope.CanSplitByRange(key) {
left, right = scope.SplitByRange(key)
} else {
left, right = scope, NewScope(NewRange(scope.Range.ExclusiveMax, scope.Range.ExclusiveMax), scope.Predicate)
} Defensive patterns
Strategy: validation
Validate before calling
if scope.CanSplitByRange(key) {
left, right = scope.SplitByRange(key)
} Prevention
- Always gate SplitByRange behind CanSplitByRange
- Compute split keys as midpoints strictly inside the range
- Skip splitting for empty or single-key scopes
When it happens
Trigger: Calling scope.SplitByRange(key) where key <= range.InclusiveMin or key >= range.ExclusiveMax; splitting an empty or single-point range; calling on a scope whose range was already split at that key.
Common situations: Queue load-balancing code that picks split points from stale range metadata; splitting an empty scope recovered from persistence; off-by-one between exclusive/inclusive bounds.
Related errors
- Unable to split queue slice with range %v at %v
- Unable to split iterator with range %v at %v
- Unable to split range %v at %v
- Can not append slice to existing list of slices, incoming sl
- Found overlapping incoming slices, left slice range: %v, rig
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/214f9f068877f413.
Report an issue: GitHub.