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
- Increase the MQTT JetStream ack timeout setting (e.g. mqtt js ack timeout in the server config) to allow for storage latency
- Check JetStream and stream health (nats stream info, cluster quorum, raft state) and restore quorum or fix storage
- Reduce message sizes / publish rate from MQTT clients and monitor server CPU/IO
- 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
- Set the server's MQTT JS ack timeout above worst-case JetStream commit latency
- Monitor JetStream raft/quorum health and disk latency with alerts
- Keep message sizes reasonable; split very large QoS1 payloads
- Use clean-session=false so QoS1 messages survive connection failure
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
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- JetStream did not acknowledge the QoS1 message within %v (se
- QoS1 in-flight window is full (%d messages) and JetStream ha
- ack wait must be a positive value
- JS API timeout must be a positive value
- mqtt requires JetStream to be enabled if running in standalo
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/d9d4913c2bb01904.
Report an issue: GitHub.