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
- No action needed; the automatic retry re-establishes catchup
- Frequent retries suggest message reordering or leader churn — check cluster stability
- 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.