nats-io/nats-server · error

create messages stream for account

Error message

create messages stream for account %q: %v

What it means

The MQTT messages stream (subject prefix mqttStreamSubjectPrefix + '>' under FileStorage with InterestPolicy) is created on first MQTT use per account. If createStream returns an error other than JSStreamNameExistErr, this wrapped error identifies which stream and account failed. Name-exists is treated as success because another server already created the stream.

Solutions

  1. Inspect the wrapped inner error for the precise JetStream failure reason.
  2. Increase the account's JS storage/stream limits or free storage.
  3. Ensure the cluster has enough nodes for the configured StreamReplicas.
  4. Verify JetStream is enabled and healthy on the server.
Defensive patterns

Strategy: retry

Validate before calling

// Check the account has free JS storage/streams before first MQTT use
if (account.jsUsage.store >= account.limits.jetstream.max_store) {
  throw new Error('account JetStream storage exhausted; MQTT messages stream will fail to create');
}

Try / catch

try {
  await mqttConnect();
} catch (e) {
  if (/create messages stream/.test(e.message)) {
    freeOrRaiseStorageQuota();
    return mqttConnect();
  }
  throw e;
}

Prevention

When it happens

Trigger: jsa.createStream(cfg) for the '<account>-mqtt-messages' stream fails with anything except JSStreamNameExistErr — e.g. account storage quota exceeded, JS API errors, or invalid replica counts vs cluster size.

Common situations: Disk/storage limits reached for the account; JetStream not enabled; replicas > available cluster nodes; temporary JS unavailability during CONNECT.

Related errors


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

Appendix: source

Thrown at server/mqtt.go:1444

			as.transferUniqueSessStreamsToMuxed(s)
		} else if isErrorOtherThan(err, JSStreamNameExistErr) {
			return nil, fmt.Errorf("create sessions stream for account %q: %v", accName, err)
		}
	}

	if si, err := lookupStream(mqttStreamName, "messages"); err != nil {
		return nil, err
	} else if si == nil {
		// Create the stream for the messages.
		cfg := &StreamConfig{
			Name:      mqttStreamName,
			Subjects:  []string{mqttStreamSubjectPrefix + ">"},
			Storage:   FileStorage,
			Retention: InterestPolicy,
			Replicas:  replicas,
		}
		if _, _, err := jsa.createStream(cfg); isErrorOtherThan(err, JSStreamNameExistErr) {
			return nil, fmt.Errorf("create messages stream for account %q: %v", accName, err)
		}
	}

	if si, err := lookupStream(mqttQoS2IncomingMsgsStreamName, "QoS2 incoming messages"); err != nil {
		return nil, err
	} else if si == nil {
		// Create the stream for the incoming QoS2 messages that have not been
		// PUBREL-ed by the sender. Subject is
		// "$MQTT.qos2.<session>.<PI>", the .PI is to achieve exactly
		// once for each PI.
		cfg := &StreamConfig{
			Name:          mqttQoS2IncomingMsgsStreamName,
			Subjects:      []string{mqttQoS2IncomingMsgsStreamSubjectPrefix + ">"},
			Storage:       FileStorage,
			Retention:     LimitsPolicy,
			Discard:       DiscardNew,
			MaxMsgsPer:    1,
			DiscardNewPer: true,

View on GitHub (pinned to 3a66a489d2)