nats-io/nats-server · error

Expected first catchup entry to be a snapshot and peerstate,

Error message

Expected first catchup entry to be a snapshot and peerstate, will retry

What it means

During catchup, the first entry received was not the expected snapshot+peerstate pair, meaning real-time or out-of-order messages arrived instead of the catchup head. No response is sent (deliberately, to avoid falsely reporting success), and the catchup process restarts to re-request from a consistent point.

Source

Thrown at server/raft.go:4749

				n.cancelCatchup()
			}
			// Intentionally not responding. Otherwise, we could erroneously report "success". Reporting
			// non-success is not needed either, and would only be wasting messages.
			// For example, if we got partial catchup, and then the "real-time" messages came in very delayed.
			// If we reported "success" on those "real-time" messages, we'd wrongfully be providing
			// quorum while not having an up-to-date log.
			n.Unlock()
			return
		}

		// Check if we are catching up. If we are here we know the leader did not have all of the entries
		// so make sure this is a snapshot entry. If it is not start the catchup process again since it
		// means we may have missed additional messages.
		if catchingUp {
			// This means we already entered into a catchup state but what the leader sent us did not match what we expected.
			// Snapshots and peerstate will always be together when a leader is catching us up in this fashion.
			if len(ae.entries) != 2 || ae.entries[0].Type != EntrySnapshot || ae.entries[1].Type != EntryPeerState {
				n.warn("Expected first catchup entry to be a snapshot and peerstate, will retry")
				n.cancelCatchup()
				n.Unlock()
				return
			}

			if ps, err := decodePeerState(ae.entries[1].Data); err == nil {
				n.processPeerState(ps)
				// Also need to copy from client's buffer.
				ae.entries[0].Data = copyBytes(ae.entries[0].Data)
			} else {
				n.warn("Could not parse snapshot peerstate correctly")
				n.cancelCatchup()
				n.Unlock()
				return
			}

			// Inherit state from appendEntry with the leader's snapshot.
			hadPreviousSnapshot := n.snapfile != _EMPTY_

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. No action needed; the automatic retry re-establishes catchup
  2. Frequent retries suggest message reordering or leader churn — check cluster stability
  3. Ensure leaders are not flapping during heavy catchup traffic
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at server/raft.go:4749 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/f171a51d979b62a7. Report an issue: GitHub.