nats-io/nats-server · error

consumer assignment error: %w

Error message

consumer assignment error: %w

What it means

During the consumer portion of a JetStream health check, the consumer assignment (ca) carries a persisted assignment-level error (ca.err) — for example the consumer failed to be created on this peer (limits, invalid config). The health check surfaces this error instead of falling through to runtime checks on a consumer that never started, so the consumer reports unhealthy.

Source

Thrown at server/jetstream_cluster.go:1104

		return errors.New("stream missing")
	}
	s, cc := js.srv, js.cluster
	if cc == nil {
		// Non-clustered mode
		js.mu.RUnlock()
		return nil
	}
	if ca == nil || ca.Group == nil {
		js.mu.RUnlock()
		return errors.New("consumer assignment or group missing")
	}
	// Surface any persisted assignment-level error (e.g. failed create on this
	// peer) so the health check reflects the broken state instead of falling
	// through to runtime-only checks.
	if ca.err != nil {
		err := ca.err
		js.mu.RUnlock()
		return fmt.Errorf("consumer assignment error: %w", err)
	}
	created := ca.Created
	node := ca.Group.node
	js.mu.RUnlock()

	// Check if not running at all.
	o := mset.lookupConsumer(consumer)
	if o == nil {
		if time.Since(created) < 5*time.Second {
			// No further checks, consumer is not available yet but should be soon.
			// We'll start erroring once we're sure this consumer is actually broken.
			return nil
		}
		return errors.New("consumer not found")
	}

	oNode := o.raftNode()
	rc, _ := o.replica()

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Unwrap the error to see the root cause (limits, invalid config) and fix it — e.g. delete unused consumers to free MaxConsumers quota, correct the consumer config
  2. Re-issue the consumer create/update via the JS API so the assignment error clears
  3. Check that all peers run compatible server versions for the consumer features used
  4. Review server logs on the peer that originally rejected the consumer for the exact failure reason
Defensive patterns

Strategy: try-catch

Validate before calling

ci, err := js.ConsumerInfo(stream, consumer)
if err != nil { /* consumer never materialized: inspect assignment error via healthz/jsz */ }

Type guard

func hasConsumerAssignmentErr(err error) bool {
    return strings.Contains(err.Error(), "consumer assignment error")
}

Try / catch

if err := healthz(); err != nil {
    cause := errors.Unwrap(err)
    log.Printf("consumer assignment unhealthy: %v", cause) // fix root cause (limits/config)
}

Prevention

When it happens

Trigger: Consumer create/update proposal failed on a peer and the error was persisted in the consumer assignment; consumer created with a config the peer cannot honor (e.g. deliver subject doesn't exist on that server version, account limits); leader election moved to a peer holding the failed assignment.

Common situations: Exceeded MaxConsumers or related account limits; DURABLE consumer config conflict across versions; partially failed consumer creation after network partition during setup.

Related errors


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