nats-io/nats-server · error

timeout after %v waiting for the JetStream ack

Error message

timeout after %v waiting for the JetStream ack

What it means

When a QoS1 MQTT PUBLISH is bridged to JetStream, the server waits (bounded by the MQTT JS ack timeout) for JetStream to acknowledge the stored message before sending PUBACK to the client. If the timer fires first, the server fails that ack with this timeout error.

Source

Thrown at server/mqtt.go:4600

	}

	for {
		select {
		case ack := <-pipe.q:
			t.Reset(jsa.timeout)
			select {
			case err := <-ack.done:
				if err != nil {
					fail(ack, err)
					return
				}
				c.mu.Lock()
				trace := c.trace
				c.mu.Unlock()
				c.mqttEnqueuePubResponse(mqttPacketPubAck, ack.pi, trace)

			case <-t.C:
				fail(ack, fmt.Errorf("timeout after %v waiting for the JetStream ack", jsa.timeout))
				return

			case <-pipe.quitCh:
				// pipe.shutdown only covers entries still queued; this one is
				// ours to clean up.
				jsa.replies.Delete(ack.reply)
				return

			case <-s.quitCh:
				// pipe.shutdown only covers entries still queued; this one is
				// ours to clean up.
				jsa.replies.Delete(ack.reply)
				return
			}

		case <-pipe.quitCh:
			return

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Increase the MQTT JetStream ack timeout setting (e.g. mqtt js ack timeout in the server config) to allow for storage latency
  2. Check JetStream and stream health (nats stream info, cluster quorum, raft state) and restore quorum or fix storage
  3. Reduce message sizes / publish rate from MQTT clients and monitor server CPU/IO
  4. Verify stream configuration (retention, limits, replicas) permits the incoming messages

Example fix

// before (server config)
mqtt { js_timeout: "5s" }
// after
mqtt { js_timeout: "30s" }
Defensive patterns

Strategy: try-catch

Try / catch

client.OnConnectionLost = func(_ mqtt.Client, err error) {
  if strings.Contains(err.Error(), "waiting for the JetStream ack") {
    log.Printf("JS ack timeout, backing off: %v", err)
    time.Sleep(backoff)
    reconnectWithSessionResume()
  }
}

Prevention

When it happens

Trigger: JetStream does not respond to the server's publish/ack within jsa.timeout — e.g. JetStream is slow, the stream is under backpressure, the account/stream is misconfigured, or the server is overloaded — while the MQTT pipe is still healthy.

Common situations: Slow disks on the JS storage, very large messages, cluster quorum loss so JS can't commit, misconfigured stream (limited retention/limits causing rejection), or heavy system load.

Understand the failure class

Related errors


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