slackhq/nebula · error

handshake message index %d exceeds replay window

Error message

handshake message index %d exceeds replay window

What it means

Replay-protection error raised while seeding a ConnectionState from a completed handshake: a handshake-stage message counter index exceeded the anti-replay window size, meaning the recorded counter values cannot be represented. This indicates a protocol violation or corrupted handshake state rather than normal traffic; the data plane would otherwise silently drop everything.

Source

Thrown at connection_state.go:58

	myCert         cert.Certificate
	peerCert       *cert.CachedCertificate
	initiator      bool
	messageCounter atomic.Uint64
	window         *Bits
	decryptLock    sync.Mutex
	writeLock      sync.Mutex
	// epoch is this session's sessionEpoch ordinal. Immutable after creation.
	epoch uint64
}

// newConnectionStateFromResult builds a fully-populated ConnectionState from a
// completed handshake.Result. It seeds messageCounter and the replay window so
// that the post-handshake message indices already used on the wire don't count
// as missed traffic in the data plane.
func newConnectionStateFromResult(r *handshake.Result) (*ConnectionState, error) {
	// Refuse a MessageIndex too big for the replay window: it can only be a bug, and would spin the seed loop below.
	if r.MessageIndex >= ReplayWindow {
		return nil, fmt.Errorf("handshake message index %d exceeds replay window", r.MessageIndex)
	}

	ci := &ConnectionState{
		myCert:    r.MyCert,
		initiator: r.Initiator,
		peerCert:  r.RemoteCert,
		eKey:      noiseutil.NewCipherState(r.EKey, r.Cipher),
		dKey:      noiseutil.NewCipherState(r.DKey, r.Cipher),
		window:    NewBits(ReplayWindow),
		epoch:     sessionEpoch.Add(1),
	}
	ci.messageCounter.Add(r.MessageIndex)
	for i := uint64(1); i <= r.MessageIndex; i++ {
		ci.window.Update(nil, i)
	}
	return ci, nil
}

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Treat as a fatal handshake failure and tear down the connection
  2. Check for a buggy or hostile peer sending out-of-range counters
  3. Upgrade both peers to compatible versions if the counter window semantics changed
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at connection_state.go:58 when the library encounters an invalid state.

Common situations: See trigger scenarios.

Understand the failure class


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/98c09482c2b20a0a. Report an issue: GitHub.