temporalio/temporal · error
version history not initialized
Error message
version history not initialized
What it means
IsLCAVersionHistoryItemAppendable compares a VersionHistory's last item against the given LCA item to decide if new events can be appended; it panics if the history has zero items. A VersionHistory must always contain at least one item (its initial branch point), so an empty Items slice indicates corrupted or improperly initialized state and the check aborts via panic.
Source
Thrown at common/persistence/versionhistory/version_history.go:201
}
func SplitVersionHistoryByLastLocalGeneratedItem(
versionHistoryItems []*historyspb.VersionHistoryItem,
initialFailoverVersion int64,
failoverVersionIncrement int64,
) (localItems []*historyspb.VersionHistoryItem, remoteItems []*historyspb.VersionHistoryItem) {
for i, versionHistoryItem := range slices.Backward(versionHistoryItems) {
if versionHistoryItem.Version%failoverVersionIncrement == initialFailoverVersion {
return versionHistoryItems[:i+1], versionHistoryItems[i+1:]
}
}
return nil, versionHistoryItems
}
// IsLCAVersionHistoryItemAppendable checks if a LCA VersionHistoryItem is appendable.
func IsLCAVersionHistoryItemAppendable(v *historyspb.VersionHistory, lcaItem *historyspb.VersionHistoryItem) bool {
if len(v.Items) == 0 {
panic("version history not initialized")
}
if lcaItem == nil {
panic("lcaItem is nil")
}
return IsEqualVersionHistoryItem(v.Items[len(v.Items)-1], lcaItem)
}
// GetFirstVersionHistoryItem return the first VersionHistoryItem.
func GetFirstVersionHistoryItem(v *historyspb.VersionHistory) (*historyspb.VersionHistoryItem, error) {
if len(v.Items) == 0 {
return nil, serviceerror.NewInternal("version history is empty.")
}
return CopyVersionHistoryItem(v.Items[0]), nil
}
// GetLastVersionHistoryItem return the last VersionHistoryItem.
func GetLastVersionHistoryItem(v *historyspb.VersionHistory) (*historyspb.VersionHistoryItem, error) {View on GitHub (pinned to bde624efd1)
Solutions
- Construct histories only via versionhistory.NewVersionHistory(NewVersionHistoryItem(...)) so at least one item always exists.
- Before calling, skip or treat as non-appendable any history with len(v.GetItems()) == 0 instead of invoking the check.
- If trimming items, enforce a minimum of one item remains.
- Validate decoded branch protos after deserialization in history replay paths.
Example fix
// before
appendable := versionhistory.IsLCAVersionHistoryItemAppendable(vh, lcaItem) // panics if vh.Items empty
// after
if len(vh.GetItems()) == 0 {
return false, nil
}
appendable := versionhistory.IsLCAVersionHistoryItemAppendable(vh, lcaItem) Defensive patterns
Strategy: validation
Validate before calling
func isAppendableSafe(vh *historyspb.VersionHistory, lca *historyspb.VersionHistoryItem) bool {
if vh == nil || len(vh.GetItems()) == 0 || lca == nil {
return false
}
return versionhistory.IsLCAVersionHistoryItemAppendable(vh, lca)
} Type guard
func isInitialized(vh *historyspb.VersionHistory) bool { return vh != nil && len(vh.GetItems()) > 0 } Try / catch
// avoid the panic path by checking initialization first
if !isInitialized(vh) { return false, nil }
return versionhistory.IsLCAVersionHistoryItemAppendable(vh, lca), nil Prevention
- Only create VersionHistory via versionhistory.NewVersionHistory so Items is never empty
- After branch trimming/filtering, assert at least one item remains
- Validate branch protos when loading from storage
When it happens
Trigger: Calling versionhistory.IsLCAVersionHistoryItemAppendable(v, lcaItem) where v is a *historyspb.VersionHistory with len(v.Items) == 0 — e.g. a manually constructed &historyspb.VersionHistory{} or a branch whose items were truncated.
Common situations: Building version histories in tests with an empty struct instead of NewVersionHistory; deserialization of a branch that lost its items; code that filters/removes items down to zero during branch trimming and then re-checks appendability.
Related errors
- version history cannot be null
- 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/d51b6de56147cb50.
Report an issue: GitHub.