nats-io/nats-server · error

lookup %s stream for account %q: %v

Error message

lookup %s stream for account %q: %v

What it means

During MQTT JetStream stream setup for an account, mqtt.jsStreamConfig looks up existing streams (messages, sessions, QoS2, retained, etc.) via jsa.lookupStream. If the lookup fails with anything other than JSStreamNotFoundErr, the error is wrapped with the role of the stream (txt) and account name so operators know which stream lookup failed. Stream-not-found is treated as normal (stream will be created), all other lookup errors are fatal here.

Source

Thrown at server/mqtt.go:1397

	// Start the go routine that will send JS API requests.
	s.startGoRoutine(func() {
		defer s.grWG.Done()
		as.sendJSAPIrequests(s, c, accName, closeCh)
	})

	// Start the go routine that will clean up cached retained messages that expired.
	s.startGoRoutine(func() {
		defer s.grWG.Done()
		as.cleanupRetainedMessageCache(s, closeCh)
	})

	lookupStream := func(stream, txt string) (*StreamInfo, error) {
		si, err := jsa.lookupStream(stream)
		if err != nil {
			if IsNatsErr(err, JSStreamNotFoundErr) {
				return nil, nil
			}
			return nil, fmt.Errorf("lookup %s stream for account %q: %v", txt, accName, err)
		}
		if opts.MQTT.StreamReplicas == 0 {
			return si, nil
		}
		sr := 1
		if si.Cluster != nil {
			sr += len(si.Cluster.Replicas)
		}
		if replicas != sr {
			s.Warnf("MQTT %s stream replicas mismatch: current is %v but configuration is %v for '%s > %s'",
				txt, sr, replicas, accName, stream)
		}
		return si, nil
	}

	if si, err := lookupStream(mqttSessStreamName, "sessions"); err != nil {
		return nil, err
	} else if si == nil {

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Read the wrapped inner error after 'lookup ... stream for account' to get the underlying JetStream cause.
  2. Enable JetStream on the server and grant the account JS permissions and limits.
  3. Check JetStream cluster health (server logs, jsz) if errors reference raft/metadata.
  4. Verify the account's JS tier/resource limits aren't exhausted.
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check server/account readiness before connecting MQTT clients
// nats account info: JetStream enabled and resources available
if (!account.jetstream || !account.jetstream.enabled) throw new Error('JetStream required for MQTT');

Try / catch

try {
  await mqttConnect();
} catch (e) {
  if (/lookup .* stream for account/.test(e.message)) {
    // JetStream lookup failed; wait for JS health then retry
    await waitForJetStreamHealthy();
    return mqttConnect();
  }
  throw e;
}

Prevention

When it happens

Trigger: jsa.lookupStream(stream) returns an error that is not JSStreamNotFoundErr — e.g. JetStream not enabled for the account, account JS resources exhausted, API/permission errors, raft/cluster issues — inside the lookupStream closure of mqttJSStreamConfig.

Common situations: MQTT enabled but JetStream not enabled on the account/server; missing JS permissions for the account; JS storage/account limits reached; cluster instability; misconfigured JS domain.

Related errors


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