{"record":{"id":"9b0c6a039294772c","repo":"nats-io/nats-server","slug":"bad-pending-entry-sequence-d-out-of-range","errorCode":null,"errorMessage":"bad pending entry, sequence [%d] out of range","messagePattern":"bad pending entry, sequence \\[(.+?)\\] out of range","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/filestore.go","lineNumber":13885,"sourceCode":"\nfunc (o *consumerFileStore) Update(state *ConsumerState) error {\n\t// Sanity checks.\n\tif state.AckFloor.Consumer > state.Delivered.Consumer {\n\t\treturn fmt.Errorf(\"bad ack floor for consumer\")\n\t}\n\tif state.AckFloor.Stream > state.Delivered.Stream {\n\t\treturn fmt.Errorf(\"bad ack floor for stream\")\n\t}\n\n\t// Copy to our state.\n\tvar pending map[uint64]*Pending\n\tvar redelivered map[uint64]uint64\n\tif len(state.Pending) > 0 {\n\t\tpending = make(map[uint64]*Pending, len(state.Pending))\n\t\tfor seq, p := range state.Pending {\n\t\t\tpending[seq] = &Pending{p.Sequence, p.Timestamp}\n\t\t\tif seq <= state.AckFloor.Stream || seq > state.Delivered.Stream {\n\t\t\t\treturn fmt.Errorf(\"bad pending entry, sequence [%d] out of range\", seq)\n\t\t\t}\n\t\t}\n\t}\n\tif len(state.Redelivered) > 0 {\n\t\tredelivered = make(map[uint64]uint64, len(state.Redelivered))\n\t\tfor seq, dc := range state.Redelivered {\n\t\t\tredelivered[seq] = dc\n\t\t}\n\t}\n\n\t// Replace our state.\n\to.mu.Lock()\n\tdefer o.mu.Unlock()\n\n\t// Check to see if this is an outdated update.\n\tif state.Delivered.Consumer < o.state.Delivered.Consumer || state.AckFloor.Stream < o.state.AckFloor.Stream {\n\t\treturn ErrStoreOldUpdate\n\t}","sourceCodeStart":13867,"sourceCodeEnd":13903,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/filestore.go#L13867-L13903","documentation":"consumerFileStore.Update() validates each pending sequence as it copies state.Pending: every pending sequence must be strictly greater than AckFloor.Stream (not yet acked) and not greater than Delivered.Stream (already delivered). A sequence outside (AckFloor.Stream, Delivered.Stream] is impossible state. Thrown from server/filestore.go.","triggerScenarios":"Passing a ConsumerState whose Pending map contains a sequence <= AckFloor.Stream (already acked) or > Delivered.Stream (never delivered) to Update().","commonSituations":"Merging pending maps from two snapshots; a consumer whose ack floor advanced but stale pending entries weren't pruned; importing state from a different stream (different sequence ranges); restoring state captured before/after compaction mismatch.","solutions":["Prune Pending entries with seq <= AckFloor.Stream before calling Update","Drop Pending entries with seq > Delivered.Stream; they must be redelivered via the stream, not stored as pending","Rebuild pending from the stream's delivered-but-unacked messages instead of importing foreign state","Log the offending seq plus ack floor/delivered to identify which snapshot source is wrong"],"exampleFix":"// before\nfor seq, p := range state.Pending {\n\tif seq <= state.AckFloor.Stream { /* stale, will fail Update */ }\n}\nstore.Update(state) // bad pending entry, sequence [%d] out of range\n// after\nfor seq := range state.Pending {\n\tif seq <= state.AckFloor.Stream || seq > state.Delivered.Stream {\n\t\tdelete(state.Pending, seq)\n\t}\n}\nstore.Update(state)","handlingStrategy":"validation","validationCode":"func prunePending(st *ConsumerState) {\n\tfor seq := range st.Pending {\n\t\tif seq <= st.AckFloor.Stream || seq > st.Delivered.Stream {\n\t\t\tdelete(st.Pending, seq)\n\t\t}\n\t}\n}\nprunePending(st); store.Update(st)","typeGuard":"func pendingInRange(st *ConsumerState) bool {\n\tfor seq := range st.Pending {\n\t\tif seq <= st.AckFloor.Stream || seq > st.Delivered.Stream { return false }\n\t}\n\treturn true\n}","tryCatchPattern":"if err := store.Update(st); err != nil {\n\tif strings.Contains(err.Error(), \"bad pending entry\") {\n\t\t// log offending seq from err text, prune, retry once\n\t}\n\treturn err\n}","preventionTips":["Prune pending entries whenever the ack floor advances","Never merge Pending maps from different consumers or streams","Snapshot ack floor, delivered, and pending atomically","Validate pending window before any Update/ForceUpdate"],"tags":["jetstream","consumer-state","filestore","pending","validation"],"backgroundTag":"consumer-state-inconsistent","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}