nats-io/nats-server · error

bad ack floor for stream

Error message

bad ack floor for stream

What it means

Sanity check in consumerMemStore.Update: the stream-sequence AckFloor is greater than the Delivered stream sequence — more stream messages acknowledged than delivered. Rejects corrupted or hand-crafted ConsumerState payloads before they overwrite local state.

Source

Thrown at server/memstore.go:2765

		// Skip if beyond our current state.
		if first, _, _ := db.State(); first > lseq {
			continue
		}
		db.Range(func(seq uint64) bool {
			ms.removeMsg(seq, false)
			return true
		})
	}
	return nil
}

func (o *consumerMemStore) Update(state *ConsumerState) error {
	// Sanity checks.
	if state.AckFloor.Consumer > state.Delivered.Consumer {
		return fmt.Errorf("bad ack floor for consumer")
	}
	if state.AckFloor.Stream > state.Delivered.Stream {
		return fmt.Errorf("bad ack floor for stream")
	}

	// Copy to our state.
	var pending map[uint64]*Pending
	var redelivered map[uint64]uint64
	if len(state.Pending) > 0 {
		pending = make(map[uint64]*Pending, len(state.Pending))
		for seq, p := range state.Pending {
			pending[seq] = &Pending{p.Sequence, p.Timestamp}
			if seq <= state.AckFloor.Stream || seq > state.Delivered.Stream {
				return fmt.Errorf("bad pending entry, sequence [%d] out of range", seq)
			}
		}
	}
	if len(state.Redelivered) > 0 {
		redelivered = make(map[uint64]uint64, len(state.Redelivered))
		for seq, dc := range state.Redelivered {
			redelivered[seq] = dc

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Validate the incoming ConsumerState before calling Update
  2. Recreate the consumer if replicated state is inconsistent
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/memstore.go:2765 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/2165cc96ca96deea. Report an issue: GitHub.