{"record":{"id":"a98cd553c50d847e","repo":"temporalio/temporal","slug":"corrupted-history-event-batch-eventid-is-not-cont","errorCode":null,"errorMessage":"corrupted history event batch, eventID is not contiguous","messagePattern":"corrupted history event batch, eventID is not contiguous","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"common/persistence/history_manager.go","lineNumber":30,"sourceCode":"\t\"go.temporal.io/api/serviceerror\"\n\tpersistencespb \"go.temporal.io/server/api/persistence/v1\"\n\t\"go.temporal.io/server/common\"\n\t\"go.temporal.io/server/common/log/tag\"\n\t\"go.temporal.io/server/common/primitives/timestamp\"\n\t\"go.temporal.io/server/common/softassert\"\n)\n\nconst (\n\tdefaultLastNodeID        = common.FirstEventID - 1\n\tdefaultLastTransactionID = int64(0)\n\n\t// TrimHistoryBranch will only dump metadata, relatively cheap\n\ttrimHistoryBranchPageSize = 1000\n\tdataLossMsg               = \"Potential data loss\"\n)\n\nvar (\n\terrNonContiguousEventID = errors.New(\"corrupted history event batch, eventID is not contiguous\")\n\terrWrongVersion         = errors.New(\"corrupted history event batch, wrong version and IDs\")\n\terrEmptyEvents          = errors.New(\"corrupted history event batch, empty events\")\n)\n\nvar _ ExecutionManager = (*executionManagerImpl)(nil)\n\n// ForkHistoryBranch forks a new branch from a old branch\nfunc (m *executionManagerImpl) ForkHistoryBranch(\n\tctx context.Context,\n\trequest *ForkHistoryBranchRequest,\n) (*ForkHistoryBranchResponse, error) {\n\n\tif request.ForkNodeID <= 1 {\n\t\treturn nil, &InvalidPersistenceRequestError{\n\t\t\tMsg: \"ForkNodeID must be > 1\",\n\t\t}\n\t}\n","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/persistence/history_manager.go#L12-L48","documentation":"errNonContiguousEventID is declared in common/persistence/history_manager.go and returned by readHistoryBranch, readHistoryBranchReverse, and ValidateBatch when a loaded history event batch has a gap in event IDs — events must be contiguous within a batch/branch. This is treated as corrupted history data, indicating a storage or replication problem, and guards against building workflows on incomplete history.","triggerScenarios":"Reading a history branch whose next/first event IDs leave a gap between batches; ValidateBatch detecting batch event IDs that do not run contiguously; database rows or Blobstore data for a branch that were partially written or deleted.","commonSituations":"Underlying persistence (DB rows or blobs) corrupted or partially deleted; version/branch metadata pointing at the wrong shard of events; bugs in history archival/trimming; disaster-recovery restores that missed some events.","solutions":["Verify persistence integrity for the affected workflow's history rows/blobs and restore from backup if corrupted","Compare the branch token/branchID and version against the events table to find the missing range","Check history service logs for the correlated dataLossMsg ('Potential data loss') to identify the exact batch","If caused by a failed migration/restore, re-run the restore and confirm event ID continuity"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"func batchesContiguous(events []*historypb.HistoryEvent) bool {\n    for i := 1; i < len(events); i++ {\n        if events[i].EventId != events[i-1].EventId+1 { return false }\n    }\n    return true\n}","typeGuard":"if len(batch.Events) == 0 || batch.Events[0].EventId != expectedFirstEventID { return errNonContiguousEventID }","tryCatchPattern":"events, err := executionManager.ReadHistoryBranch(ctx, req)\nif errors.Is(err, persistence.ErrNonContiguousEventID) {\n    // alert, quarantine the workflow, and investigate persistence/restore integrity\n}","preventionTips":["Monitor for this error and the correlated 'Potential data loss' log line with paging alerts","Verify backups/restores cover all history event ranges before promoting them","After trimming/archival operations, run ValidateBatch on sampled branches","Treat any occurrence as a storage-integrity incident, not a transient retryable failure"],"tags":["persistence","history","data-corruption"],"backgroundTag":"history-data-corruption","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}