temporalio/temporal · error

Can not append slice to existing list of slices, incoming sl

Error message

Can not append slice to existing list of slices, incoming slice range: %v, existing slice range: %v 

What it means

ReaderImpl.AppendSlices panics when the first incoming slice starts before the end of the last slice already held by the reader, i.e. the append would make the reader's slice list non-ordered. AppendSlices is meant for strictly new, later task-key ranges; the reader expects its slices to be sorted and non-overlapping at all times. This is a programmer-invariant panic, not a runtime I/O error.

Source

Thrown at service/history/queues/reader.go:287

	r.resetNextReadSliceLocked()
	r.monitor.SetSliceCount(r.readerID, r.slices.Len())
}

func (r *ReaderImpl) AppendSlices(incomingSlices ...Slice) {
	if len(incomingSlices) == 0 {
		return
	}

	validateSlicesOrderedDisjoint(incomingSlices)

	r.Lock()
	defer r.Unlock()

	if back := r.slices.Back(); back != nil {
		lastSliceRange := back.Value.(Slice).Scope().Range
		firstIncomingRange := incomingSlices[0].Scope().Range
		if lastSliceRange.ExclusiveMax.CompareTo(firstIncomingRange.InclusiveMin) > 0 {
			panic(fmt.Sprintf(
				"Can not append slice to existing list of slices, incoming slice range: %v, existing slice range: %v ",
				firstIncomingRange,
				lastSliceRange,
			))
		}
	}

	for _, incomingSlice := range incomingSlices {
		if scope := incomingSlice.Scope(); scope.IsEmpty() {
			continue
		}
		r.slices.PushBack(incomingSlice)
	}

	r.resetNextReadSliceLocked()
	r.monitor.SetSliceCount(r.readerID, r.slices.Len())
}

View on GitHub (pinned to bde624efd1)

Solutions

  1. Use MergeSlices (which sorts and merges overlapping slices) instead of AppendSlices when ordering is not guaranteed
  2. Before appending, check the reader's last slice range and confirm incomingSlices[0].Scope().Range.InclusiveMin >= last.ExclusiveMax
  3. Sort incomingSlices by InclusiveMin and drop/merge any that overlap existing ranges before calling AppendSlices

Example fix

// before
reader.AppendSlices(newSlice) // panics: overlaps existing tail

// after
reader.MergeSlices(newSlice) // sorts and merges, no panic
Defensive patterns

Strategy: validation

Validate before calling

// caller-side check before AppendSlices
func canAppend(r *queues.Reader, incoming []queues.Slice) bool {
  if len(incoming) == 0 { return true }
  first := incoming[0].Scope().Range
  return first.InclusiveMin.CompareTo(lastExclusiveMax(r)) <= 0 // reader's last slice ExclusiveMax
}

Prevention

When it happens

Trigger: Calling reader.AppendSlices(s...) when reader's last slice has ExclusiveMax > s[0].InclusiveMin. Happens when a caller computes slices out of order, or calls AppendSlices instead of MergeSlices for ranges that overlap or precede existing slices.

Common situations: Rebuilding slices after a persistence failure and re-appending stale/older ranges; a task-id ordering assumption changing after an upgrade; concurrent producers appending overlapping shard ranges to the same reader.

Related errors


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