temporalio/temporal · error

len(expectedHistoryEvents) != len(actualHistoryEvents)

Error message

len(expectedHistoryEvents) != len(actualHistoryEvents)

What it means

HistoryRequire.EqualHistoryEvents compares expected and actual history event lists; before sanitizing event IDs/versions element-by-element it requires both slices to have identical length. If lengths differ it panics, because pairwise comparison is impossible and the caller must provide lists of the same size.

Source

Thrown at common/testing/historyrequire/history_require.go:311

	actualCompactHistory := h.formatHistoryEvents(actualHistoryEvents, true)

	startPos := strings.Index(actualCompactHistory, expectedCompactHistory)
	require.GreaterOrEqual(h.t, startPos, 0, "Expected history is not found in actual history. Expected:\n%s\nActual:\n%s", expectedCompactHistory, actualCompactHistory)
	actualHistoryEventsFirstIndex := strings.Count(actualCompactHistory[:startPos], "\n")

	h.equalHistoryEventsAttributes(expectedEventsAttributes, actualHistoryEvents[actualHistoryEventsFirstIndex:])
}

// sanitizeActualHistoryEventsForEquals clears EventID and Version fields from actual history events
// if they are not set in the CORRESPONDING expected history event.
// The length of expectedHistoryEvents and actualHistoryEvents must be equal.
func (h HistoryRequire) sanitizeActualHistoryEventsForEquals(
	expectedHistoryEvents []*historypb.HistoryEvent,
	actualHistoryEvents []*historypb.HistoryEvent,
) []*historypb.HistoryEvent {

	if len(expectedHistoryEvents) != len(actualHistoryEvents) {
		panic("len(expectedHistoryEvents) != len(actualHistoryEvents)")
	}

	var sanitizedActualHistoryEvents []*historypb.HistoryEvent
	for i, actualHistoryEvent := range actualHistoryEvents {
		sanitizeEventID := expectedHistoryEvents[i].GetEventId() == 0
		sanitizeVersion := expectedHistoryEvents[i].GetVersion() == 0

		if !sanitizeEventID && !sanitizeVersion {
			sanitizedActualHistoryEvents = append(sanitizedActualHistoryEvents, actualHistoryEvent)
			continue
		}

		sanitizedActualHistoryEvent := proto.Clone(actualHistoryEvent).(*historypb.HistoryEvent)
		if sanitizeEventID {
			sanitizedActualHistoryEvent.EventId = 0
		}
		if sanitizeVersion {
			sanitizedActualHistoryEvent.Version = 0

View on GitHub (pinned to bde624efd1)

Solutions

  1. Print both slice lengths and diff the event types to find the missing/extra event, then update the expected events fixture.
  2. Filter the actual events before comparison if unrelated event types are expected to differ (or use historyrequire APIs that tolerate length mismatch).
  3. If the code change legitimately alters history, regenerate expected events with the current history output.
Defensive patterns

Strategy: validation

Validate before calling

if len(expected) != len(actual) {
	t.Fatalf("history length mismatch: expected=%d actual=%d", len(expected), len(actual))
}

Prevention

When it happens

Trigger: Calling EqualHistoryEvents (or its anonymous wrapper) with expectedHistoryEvents and actualHistoryEvents slices of different lengths — e.g. the workflow emitted an extra/missing event vs the expected fixture.

Common situations: An integration test asserting workflow history where a new activity, signal, or timer adds an unexpected event; a fixture built for an older workflow definition; version changes adding replay events.

Related errors


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