nats-io/nats-server · critical

%w for stream '%s > %s'

Error message

%w for stream '%s > %s'

What it means

When a stream message consumer/catch-up routine (processInboundMsg on a mirror/source or raft catch-up path) is running and the raft/node loses its leader, it retries with a sleep interval. If the group is still leaderless on the first retry (numRetries == 0 and n.Leaderless()), it aborts with fmt.Errorf("%w for stream '%s > %s'", errCatchupAbortedNoLeader, ...), wrapping errCatchupAbortedNoLeader so callers can detect the catch-up was aborted because there is no raft leader to sync from.

Source

Thrown at server/jetstream_cluster.go:12496

	const maxRetries = 3
	var numRetries int

RETRY:
	// On retry, we need to release the semaphore we got. Call will be no-op
	// if releaseSem boolean has not been set to true on successfully getting
	// the semaphore.
	releaseSyncOutSem()

	if n.Leaderless() {
		// Prevent us from spinning if we've installed a snapshot from a leader but there's no leader online.
		// We wait a bit to check if a leader has come online in the meantime, if so we can continue.
		var canContinue bool
		if numRetries == 0 {
			time.Sleep(startInterval)
			canContinue = !n.Leaderless()
		}
		if !canContinue {
			return fmt.Errorf("%w for stream '%s > %s'", errCatchupAbortedNoLeader, mset.account(), mset.name())
		}
	}

	// If we have a sub clear that here.
	if sub != nil {
		s.sysUnsubscribe(sub)
		sub = nil
	}

	if !s.isRunning() {
		return ErrServerNotRunning
	}

	numRetries++
	if numRetries > maxRetries {
		// Force a hard reset here.
		return errCatchupTooManyRetries
	}

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Restore quorum: bring the required number of JetStream servers back online so a leader can be elected.
  2. Check `nats server request JetStream` / `nats str info <stream>` for peer/leader status and fix any partitioned node.
  3. After quorum is restored the catch-up retries; if it stays aborted, restart the affected replica server.
  4. Space out rolling restarts so the leader is never removed before a new one is elected.
Defensive patterns

Strategy: retry

Validate before calling

// before starting mirrors/sources or relying on catch-up, check leader presence
si, _ := js.StreamInfo(name)
if si.Cluster != nil && si.Cluster.Leader == "" {
    // leaderless: wait before triggering work that requires catch-up
}

Try / catch

err := doCatchup()
if errors.Is(err, errCatchupAbortedNoLeader) {
    // exponential backoff until the group elects a leader
    retryWithBackoff(doCatchup)
}

Prevention

When it happens

Trigger: A stream replica (or mirror/source consumer) attempts to catch up while the stream's raft group has no elected leader — e.g. the leader just crashed, a majority of peers are down, or a rolling restart removed the leader before a new election completed.

Common situations: Clusters operating with degraded quorum; maintenance windows where multiple JetStream servers restart simultaneously; network partitions isolating the leader.

Related errors


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