temporalio/temporal · error
Unable to merge queue slice of type %T with type %T
Error message
Unable to merge queue slice of type %T with type %T
What it means
SliceImpl.MergeWithSlice also panics if the incoming slice cannot be type-asserted to *SliceImpl. The merge implementation needs concrete SliceImpl internals (scope, iterators, executable tracker); any other implementation of the Slice interface cannot be merged. This guards against mixing slice implementations.
Source
Thrown at service/history/queues/slice.go:176
func (s *SliceImpl) CanMergeWithSlice(slice Slice) bool {
s.stateSanityCheck()
return s != slice && s.scope.Range.CanMerge(slice.Scope().Range)
}
func (s *SliceImpl) MergeWithSlice(slice Slice) []Slice {
if s.scope.Range.InclusiveMin.CompareTo(slice.Scope().Range.InclusiveMin) > 0 {
return slice.MergeWithSlice(s)
}
if !s.CanMergeWithSlice(slice) {
panic(fmt.Sprintf("Unable to merge queue slice having scope %v with slice having scope %v", s.scope, slice.Scope()))
}
incomingSlice, ok := slice.(*SliceImpl)
if !ok {
panic(fmt.Sprintf("Unable to merge queue slice of type %T with type %T", s, slice))
}
if s.scope.CanMergeByRange(incomingSlice.scope) {
return []Slice{s.mergeByRange(incomingSlice)}
}
mergedSlices := make([]Slice, 0, 3)
currentLeftSlice, currentRightSlice := s.splitByRange(incomingSlice.Scope().Range.InclusiveMin)
mergedSlices = appendMergedSlice(mergedSlices, currentLeftSlice)
if currentRightMax := currentRightSlice.Scope().Range.ExclusiveMax; incomingSlice.CanSplitByRange(currentRightMax) {
leftIncomingSlice, rightIncomingSlice := incomingSlice.splitByRange(currentRightMax)
mergedMidSlice := currentRightSlice.mergeByPredicate(leftIncomingSlice)
mergedSlices = appendMergedSlice(mergedSlices, mergedMidSlice)
mergedSlices = appendMergedSlice(mergedSlices, rightIncomingSlice)
} else {
currentMidSlice, currentRightSlice := currentRightSlice.splitByRange(incomingSlice.Scope().Range.ExclusiveMax)
mergedMidSlice := currentMidSlice.mergeByPredicate(incomingSlice)View on GitHub (pinned to bde624efd1)
Solutions
- Pass only concrete *SliceImpl values created via NewSlice/NewSliceImpl
- Unwrap any decorator/wrapper to the underlying *SliceImpl before merging
- In tests, use the real slice constructor instead of mock Slice implementations
Example fix
// before
slice.MergeWithSlice(mockSlice) // panics: not *SliceImpl
// after
impl, ok := wrapped.(*queues.SliceImpl)
if !ok {
return nil // or unwrap the decorator
}
result := slice.MergeWithSlice(impl) Defensive patterns
Strategy: type-guard
Validate before calling
if _, ok := other.(*queues.SliceImpl); !ok {
return nil // or unwrap; cannot merge non-SliceImpl
} Type guard
func asSliceImpl(s queues.Slice) (*queues.SliceImpl, bool) {
impl, ok := s.(*queues.SliceImpl)
return impl, ok
} Try / catch
func safeMerge(s *queues.SliceImpl, other queues.Slice) (result []queues.Slice) {
defer func() {
if r := recover(); r != nil {
result = nil
}
}()
return s.MergeWithSlice(other)
} Prevention
- Only construct slices via the package's constructors
- Unwrap wrappers before handing slices to merge/compact APIs
- Avoid mocking the Slice interface in tests; use real SliceImpl
When it happens
Trigger: Passing a custom or wrapper type implementing the Slice interface (not *SliceImpl) to MergeWithSlice; passing a nil Slice with a non-nil interface value; wrapping slices in decorators for instrumentation.
Common situations: Test code supplying mock Slice implementations; production wrappers adding metrics/logging around slices; DI swaps introducing an alternate slice type.
Related errors
- Unable to compact queue slice of type %T with type %T
- Can not append slice to existing list of slices, incoming sl
- Found overlapping incoming slices, left slice range: %v, rig
- reader with ID %v already exists
- Unable to split scope with range %v at %v
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/e6e123d8aa9d83d5.
Report an issue: GitHub.