{"record":{"id":"d51b6de56147cb50","repo":"temporalio/temporal","slug":"version-history-not-initialized","errorCode":null,"errorMessage":"version history not initialized","messagePattern":"version history not initialized","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/persistence/versionhistory/version_history.go","lineNumber":201,"sourceCode":"}\n\nfunc SplitVersionHistoryByLastLocalGeneratedItem(\n\tversionHistoryItems []*historyspb.VersionHistoryItem,\n\tinitialFailoverVersion int64,\n\tfailoverVersionIncrement int64,\n) (localItems []*historyspb.VersionHistoryItem, remoteItems []*historyspb.VersionHistoryItem) {\n\tfor i, versionHistoryItem := range slices.Backward(versionHistoryItems) {\n\t\tif versionHistoryItem.Version%failoverVersionIncrement == initialFailoverVersion {\n\t\t\treturn versionHistoryItems[:i+1], versionHistoryItems[i+1:]\n\t\t}\n\t}\n\treturn nil, versionHistoryItems\n}\n\n// IsLCAVersionHistoryItemAppendable checks if a LCA VersionHistoryItem is appendable.\nfunc IsLCAVersionHistoryItemAppendable(v *historyspb.VersionHistory, lcaItem *historyspb.VersionHistoryItem) bool {\n\tif len(v.Items) == 0 {\n\t\tpanic(\"version history not initialized\")\n\t}\n\tif lcaItem == nil {\n\t\tpanic(\"lcaItem is nil\")\n\t}\n\n\treturn IsEqualVersionHistoryItem(v.Items[len(v.Items)-1], lcaItem)\n}\n\n// GetFirstVersionHistoryItem return the first VersionHistoryItem.\nfunc GetFirstVersionHistoryItem(v *historyspb.VersionHistory) (*historyspb.VersionHistoryItem, error) {\n\tif len(v.Items) == 0 {\n\t\treturn nil, serviceerror.NewInternal(\"version history is empty.\")\n\t}\n\treturn CopyVersionHistoryItem(v.Items[0]), nil\n}\n\n// GetLastVersionHistoryItem return the last VersionHistoryItem.\nfunc GetLastVersionHistoryItem(v *historyspb.VersionHistory) (*historyspb.VersionHistoryItem, error) {","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/persistence/versionhistory/version_history.go#L183-L219","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nappendable := versionhistory.IsLCAVersionHistoryItemAppendable(vh, lcaItem) // panics if vh.Items empty\n// after\nif len(vh.GetItems()) == 0 {\n    return false, nil\n}\nappendable := versionhistory.IsLCAVersionHistoryItemAppendable(vh, lcaItem)","handlingStrategy":"validation","validationCode":"func isAppendableSafe(vh *historyspb.VersionHistory, lca *historyspb.VersionHistoryItem) bool {\n    if vh == nil || len(vh.GetItems()) == 0 || lca == nil {\n        return false\n    }\n    return versionhistory.IsLCAVersionHistoryItemAppendable(vh, lca)\n}","typeGuard":"func isInitialized(vh *historyspb.VersionHistory) bool { return vh != nil && len(vh.GetItems()) > 0 }","tryCatchPattern":"// avoid the panic path by checking initialization first\nif !isInitialized(vh) { return false, nil }\nreturn versionhistory.IsLCAVersionHistoryItemAppendable(vh, lca), nil","preventionTips":["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"],"tags":["persistence","panic","version-history","empty-state"],"backgroundTag":"version-history-not-initialized","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}