temporalio/temporal · error
version history cannot be null
Error message
version history cannot be null
What it means
NewVersionHistories wraps an initial VersionHistory into the VersionHistories container used by execution state; it panics immediately if the input VersionHistory is nil. A VersionHistories with no first branch is structurally meaningless (CurrentVersionHistoryIndex would point at nothing), so the constructor enforces the non-nil invariant at creation time.
Source
Thrown at common/persistence/versionhistory/version_histories.go:11
package versionhistory
import (
"go.temporal.io/api/serviceerror"
historyspb "go.temporal.io/server/api/history/v1"
)
// NewVersionHistories create a new instance of VersionHistories.
func NewVersionHistories(versionHistory *historyspb.VersionHistory) *historyspb.VersionHistories {
if versionHistory == nil {
panic("version history cannot be null")
}
return &historyspb.VersionHistories{
CurrentVersionHistoryIndex: 0,
Histories: []*historyspb.VersionHistory{versionHistory},
}
}
// Copy VersionHistories.
func CopyVersionHistories(h *historyspb.VersionHistories) *historyspb.VersionHistories {
var histories []*historyspb.VersionHistory
for _, history := range h.Histories {
histories = append(histories, CopyVersionHistory(history))
}
return &historyspb.VersionHistories{
CurrentVersionHistoryIndex: h.CurrentVersionHistoryIndex,
Histories: histories,View on GitHub (pinned to bde624efd1)
Solutions
- Pass a freshly constructed branch, e.g. NewVersionHistories(NewVersionHistory(NewVersionHistoryItem(firstEventID, firstVersion))), when bootstrapping a new execution.
- Guard the input: if the source VersionHistory is nil, create a default initial version history instead of passing nil through.
- Check that the proto field you sourced the history from (branch token / mutable state) is actually populated before calling.
- Upgrade/sync cluster versions if nil histories come from older persisted state.
Example fix
// before
histories := versionhistory.NewVersionHistories(mutableState.GetVersionHistories().GetHistories()[idx]) // may be nil
// after
vh := mutableState.GetVersionHistories().GetHistories()[idx]
if vh == nil {
vh = versionhistory.NewVersionHistory(versionhistory.NewVersionHistoryItem(1, 1))
}
histories := versionhistory.NewVersionHistories(vh) Defensive patterns
Strategy: validation
Validate before calling
func safeNewVersionHistories(vh *historyspb.VersionHistory) (*historyspb.VersionHistories, error) {
if vh == nil || len(vh.GetItems()) == 0 {
return nil, errors.New("input version history is nil or empty")
}
return versionhistory.NewVersionHistories(vh), nil
} Type guard
func versionHistoryExists(vh *historyspb.VersionHistory) bool { return vh != nil && len(vh.GetItems()) > 0 } Try / catch
// Go panics cannot be caught as errors; guard the input instead of recovering
if vh == nil { return nil, internalErr }
histories := versionhistory.NewVersionHistories(vh) Prevention
- Bootstrap executions only via NewVersionHistory(NewVersionHistoryItem(...)) defaults
- Validate mutable state protos after deserialization (version skew checks)
- Never pass proto sub-message fields straight into constructors without nil checks
When it happens
Trigger: Calling versionhistory.NewVersionHistories(nil), typically when the caller obtained the VersionHistory from a proto field (e.g. mutableState.VersionHistories or a branch token lookup) that was unset, or when building execution info from partially decoded state.
Common situations: Replaying history where the versioning info proto is missing/old (version skew between clusters); test helpers passing a nil branch; constructing WorkflowExecutionInfo from a mutable state blob that predates versioning.
Related errors
- version history not initialized
- lcaItem is nil
- invalid version history item event ID: %v, version: %v
- unable to decode cassandra serial consistency: %v
- invalid task schema version
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/0ed5888bf6f30a5b.
Report an issue: GitHub.