{"record":{"id":"b4792b1b6fd04874","repo":"temporalio/temporal","slug":"w-ref-transition-count-out-of-range-for-version","errorCode":null,"errorMessage":"%w: ref transition count out of range for version %v: %v not in [%v, %v]","messagePattern":"%w: ref transition count out of range for version (.+?): (.+?) not in \\[(.+?), (.+?)\\]","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/persistence/transitionhistory/transition_history.go","lineNumber":115,"sourceCode":"\t\t\t)\n\t\t}\n\t\treturn fmt.Errorf(\n\t\t\t\"%w: state namespace failover version > ref namespace failover version: %v > %v\",\n\t\t\tconsts.ErrStaleReference,\n\t\t\tlastItem.NamespaceFailoverVersion,\n\t\t\trefVersionedTransition.NamespaceFailoverVersion,\n\t\t)\n\t}\n\tif idx == len(history)-1 && maxTransitionCount < refVersionedTransition.TransitionCount {\n\t\treturn fmt.Errorf(\n\t\t\t\"%w: state transition count < ref transition count: %v < %v\",\n\t\t\tconsts.ErrStaleState,\n\t\t\tmaxTransitionCount,\n\t\t\trefVersionedTransition.TransitionCount,\n\t\t)\n\t}\n\tif minTransitionCount > refVersionedTransition.TransitionCount || maxTransitionCount < refVersionedTransition.TransitionCount {\n\t\treturn fmt.Errorf(\n\t\t\t\"%w: ref transition count out of range for version %v: %v not in [%v, %v]\",\n\t\t\tconsts.ErrStaleReference,\n\t\t\trefVersionedTransition.NamespaceFailoverVersion,\n\t\t\trefVersionedTransition.TransitionCount,\n\t\t\tminTransitionCount,\n\t\t\tmaxTransitionCount,\n\t\t)\n\t}\n\treturn nil\n}\n\n// transitionHistoryRangeForVersion finds the index and transition count range in the given history for the given version.\nfunc transitionHistoryRangeForVersion(\n\thistory []*persistencespb.VersionedTransition,\n\tversion int64,\n) (idx int, minTransitionCount int64, maxTransitionCount int64) {\n\tprevVersionMaxTransitionCount := int64(-1)\n\tfor i, item := range history {","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/persistence/transitionhistory/transition_history.go#L97-L133","documentation":"StalenessCheck verifies that a task/request's imprinted VersionedTransition reference (namespace failover version + transition count) actually exists within the target workflow's stored transition history. This error is returned (wrapping history/consts.ErrStaleReference) when the reference's namespace failover version IS present in the history, but its TransitionCount falls outside the valid range [min+1, max] for that version, meaning the reference points to an impossible or already-superseded state (e.g. after split-brain reconciliation).","triggerScenarios":"Calling StalenessCheck (directly or via IsStale, GetOrPollWorkflowMutableState, applyBackfillEvents, or ReplicateVersionedTransition) with a ref whose NamespaceFailoverVersion matches an entry in the history, but whose TransitionCount is either below the previous version's max+1 (reference predates that version's window) or above that version's recorded max (reference claims more transitions than the state has ever recorded).","commonSituations":"A duplicate/stale task or replication task referencing transition counts the history node never recorded; a workflow whose mutable state was rebuilt or truncated after failover so its history shrank below the caller's reference; split-brain repair reconciling two nodes with divergent histories; clocks/version skew after namespace failover where a ref carries a version present in history but counts from a divergent branch.","solutions":["Treat as a terminal ErrStaleReference: drop or discard the stale task/request rather than retrying against this state","Reload the workflow mutable state from persistence and re-derive the current versioned transition reference before re-attempting","Verify replication/reconciliation logic is not fabricating transition counts beyond the recorded per-version max","Check for split-brain (two history shards active) or a sharding/history-rollback incident and reconcile state"],"exampleFix":"// before: retrying on any staleness error\ncallWithState(...)\n// after: check terminal stale reference and reload\nerr := transitionhistory.StalenessCheck(ms.VersionedTransitions, ref)\nif errors.Is(err, consts.ErrStaleState) || errors.Is(err, consts.ErrStaleReference) {\n    ms, err = shards.ReloadWorkflowMutableState(ctx, ref.WorkflowKey)\n    // handle reload, then retry once with fresh state\n}","handlingStrategy":"type-guard","validationCode":"// before using a ref against a state, pre-check locally\nfunc refInRange(history []*persistencespb.VersionedTransition, ref *persistencespb.VersionedTransition) bool {\n    if len(history) == 0 || ref == nil { return false }\n    for i, item := range history {\n        if item.NamespaceFailoverVersion == ref.NamespaceFailoverVersion {\n            min := int64(0)\n            if i > 0 { min = history[i-1].TransitionCount + 1 }\n            return ref.TransitionCount >= min && ref.TransitionCount <= item.TransitionCount\n        }\n    }\n    return false\n}","typeGuard":"func isStaleReference(err error) bool {\n    return errors.Is(err, consts.ErrStaleReference)\n}","tryCatchPattern":"if err := transitionhistory.StalenessCheck(state.VersionedTransitions, ref); err != nil {\n    if errors.Is(err, consts.ErrStaleReference) {\n        // terminal: discard/refetch, do not retry against same state\n        ms, rerr := reloadMutableState(ctx, key)\n        ...\n    }\n    return err\n}","preventionTips":["Always reload mutable state before reusing an imprinted versioned transition reference","Monitor for split-brain / duplicate shard ownership which produces impossible refs","Never fabricate transition counts in replication or reconciliation code paths","Use errors.Is against consts.ErrStaleState vs consts.ErrStaleReference to decide retry vs discard"],"tags":["go","temporal","stale-reference","versioned-transition","history-shard"],"backgroundTag":"stale-transition-reference","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}