{"record":{"id":"86d91cd6a2f2d410","repo":"temporalio/temporal","slug":"unable-to-compact-queue-slice-of-type-t-with-type","errorCode":null,"errorMessage":"Unable to compact queue slice of type %T with type %T","messagePattern":"Unable to compact queue slice of type %T with type %T","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/history/queues/slice.go","lineNumber":282,"sourceCode":"\tif len(iterators) == 0 {\n\t\treturn []Iterator{iterator}\n\t}\n\n\tsize := len(iterators)\n\tif iterators[size-1].CanMerge(iterator) {\n\t\titerators[size-1] = iterators[size-1].Merge(iterator)\n\t\treturn iterators\n\t}\n\n\treturn append(iterators, iterator)\n}\n\nfunc (s *SliceImpl) CompactWithSlice(slice Slice) Slice {\n\ts.stateSanityCheck()\n\n\tincomingSlice, ok := slice.(*SliceImpl)\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"Unable to compact queue slice of type %T with type %T\", s, slice))\n\t}\n\tincomingSlice.stateSanityCheck()\n\n\tcompactedScope := NewScope(\n\t\tNewRange(\n\t\t\ttasks.MinKey(s.scope.Range.InclusiveMin, incomingSlice.scope.Range.InclusiveMin),\n\t\t\ttasks.MaxKey(s.scope.Range.ExclusiveMax, incomingSlice.scope.Range.ExclusiveMax),\n\t\t),\n\t\ttasks.OrPredicates(s.scope.Predicate, incomingSlice.scope.Predicate),\n\t)\n\n\tcompactedTaskTracker := s.merge(incomingSlice.executableTracker)\n\tcompactedIterators := s.mergeIterators(incomingSlice)\n\n\ts.destroy()\n\tincomingSlice.destroy()\n\n\treturn s.newSlice(","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/history/queues/slice.go#L264-L300","documentation":"SliceImpl.CompactWithSlice panics if the incoming slice cannot be type-asserted to *SliceImpl. Compaction merges two slices' executable trackers, iterators, and predicates (ORed) into one slice covering the union range, and requires concrete SliceImpl internals. Like the merge case, it rejects any foreign Slice implementation.","triggerScenarios":"Calling CompactWithSlice with a wrapper/mock implementing Slice but not *SliceImpl; passing a typed-nil or non-nil interface holding another implementation; custom slices introduced for testing or instrumentation.","commonSituations":"Mock slices in unit tests of compaction logic; decorators around slices for observability; refactors that changed the concrete type while older call sites passed the old wrapper.","solutions":["Pass only concrete *SliceImpl values to CompactWithSlice","Unwrap decorators/wrappers to the underlying *SliceImpl before compacting","Replace test mocks of Slice with real slices built via the package constructor"],"exampleFix":"// before\ncompact := s.CompactWithSlice(wrapperSlice) // panics: not *SliceImpl\n\n// after\nimpl, ok := wrapperSlice.(*queues.SliceImpl)\nif !ok {\n  return nil\n}\ncompact := s.CompactWithSlice(impl)","handlingStrategy":"type-guard","validationCode":"if _, ok := other.(*queues.SliceImpl); !ok {\n  return nil // cannot compact non-SliceImpl\n}","typeGuard":"func asSliceImpl(s queues.Slice) (*queues.SliceImpl, bool) {\n  impl, ok := s.(*queues.SliceImpl)\n  return impl, ok\n}","tryCatchPattern":"func safeCompact(s *queues.SliceImpl, other queues.Slice) (result queues.Slice) {\n  defer func() {\n    if r := recover(); r != nil {\n      result = nil\n    }\n  }()\n  return s.CompactWithSlice(other)\n}","preventionTips":["Pass only *SliceImpl values to CompactWithSlice","Unwrap any instrumentation wrapper to the concrete slice first","Keep slice types uniform across reader/compaction code paths"],"tags":["go","history-service","task-queue","type-assertion","panic"],"backgroundTag":"slice-type-mismatch","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}