nats-io/nats-server · error

unable to persist session %q (seq=%v): %v

Error message

unable to persist session %q (seq=%v): %v

What it means

Returned when storing the persisted session record fails: sess.jsa.storeSessionMsg publishes the session state to the '$MQTT.sess' stream and the returned error is wrapped with the session ID, sequence, and cause. The session state could not be durably saved.

Source

Thrown at server/mqtt.go:3435

	sess.mu.Unlock()

	var hdr int
	if seq != 0 {
		bb := bytes.Buffer{}
		bb.WriteString(hdrLine)
		bb.WriteString(JSExpectedLastSubjSeq)
		bb.WriteString(":")
		bb.WriteString(strconv.FormatInt(int64(seq), 10))
		bb.WriteString(CR_LF)
		bb.WriteString(CR_LF)
		hdr = bb.Len()
		bb.Write(b)
		b = bb.Bytes()
	}

	resp, err := sess.jsa.storeSessionMsg(domainTk, cidHash, hdr, b)
	if err != nil {
		return fmt.Errorf("unable to persist session %q (seq=%v): %v", ps.ID, seq, err)
	}
	// Guard before dereferencing below.
	if resp == nil || resp.PubAck == nil {
		return fmt.Errorf("unable to persist session %q (seq=%v): invalid pub ack response", ps.ID, seq)
	}
	sess.mu.Lock()
	sess.seq = resp.Sequence
	sess.mu.Unlock()
	return nil
}

// Clear the session.
//
// Runs from the client's readLoop.
// Lock not held on entry, but session is in the locked map.
func (sess *mqttSession) clear(noWait bool) error {
	var durs []string
	var pubRelDur string

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Check JetStream/stream health for $MQTT.sess and cluster quorum
  2. Reduce session state size (fewer subscriptions / queued messages) if hitting max_payload
  3. Free disk space or fix filestore issues
  4. Retry the CONNECT/publish after the underlying JetStream error is resolved

Example fix

// before
// store fails: payload too large
// after
// raise max_payload or reduce per-session state (clean_session=true, fewer subs)
null
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check stream state and payload budget before large sessions
const info = await fetch('http://monitor:8222/jsz?streams=true').then(r=>r.json())
const sess = info.account_details?.flatMap(a=>a.streams||[]).find(s=>s.name==='$MQTT.sess')
if (!sess || sess.state.messages < 0) throw new Error('$MQTT.sess stream unhealthy')

Try / catch

try {
  await mqttConnect()
} catch (e) {
  if (String(e).includes('unable to persist session')) {
    await waitForJetStreamHealthy()
    await mqttConnect({ cleanSession: true }) // fallback to avoid heavy persisted state
  } else { throw e }
}

Prevention

When it happens

Trigger: storeSessionMsg returns a JetStream error — stream not available, publish timeout, no responders, maximum payload exceeded (many subscriptions/queued messages making the record too large), or storage failure.

Common situations: JetStream degraded or restarted; cluster without quorum for the $MQTT.sess stream; MQTT session with an enormous state exceeding max_payload; disk full.

Related errors


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