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 = 0View on GitHub (pinned to bde624efd1)
Solutions
- Print both slice lengths and diff the event types to find the missing/extra event, then update the expected events fixture.
- Filter the actual events before comparison if unrelated event types are expected to differ (or use historyrequire APIs that tolerate length mismatch).
- 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
- Regenerate expected-history fixtures whenever workflow logic changes.
- Diff event type lists before calling EqualHistoryEvents to localize mismatches.
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
- panic(err)
- panic(err)
- parallelsuite: assertion called on %q after Run() was called
- GetActivityTaskScheduledEventAttributes is not set
- missing RespondWorkflowTaskCompletedRequest return
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/e674e67a67e6a573.
Report an issue: GitHub.