{"record":{"id":"d9d4913c2bb01904","repo":"nats-io/nats-server","slug":"timeout-after-v-waiting-for-the-jetstream-ack","errorCode":null,"errorMessage":"timeout after %v waiting for the JetStream ack","messagePattern":"timeout after (.+?) waiting for the JetStream ack","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mqtt.go","lineNumber":4600,"sourceCode":"\t}\n\n\tfor {\n\t\tselect {\n\t\tcase ack := <-pipe.q:\n\t\t\tt.Reset(jsa.timeout)\n\t\t\tselect {\n\t\t\tcase err := <-ack.done:\n\t\t\t\tif err != nil {\n\t\t\t\t\tfail(ack, err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tc.mu.Lock()\n\t\t\t\ttrace := c.trace\n\t\t\t\tc.mu.Unlock()\n\t\t\t\tc.mqttEnqueuePubResponse(mqttPacketPubAck, ack.pi, trace)\n\n\t\t\tcase <-t.C:\n\t\t\t\tfail(ack, fmt.Errorf(\"timeout after %v waiting for the JetStream ack\", jsa.timeout))\n\t\t\t\treturn\n\n\t\t\tcase <-pipe.quitCh:\n\t\t\t\t// pipe.shutdown only covers entries still queued; this one is\n\t\t\t\t// ours to clean up.\n\t\t\t\tjsa.replies.Delete(ack.reply)\n\t\t\t\treturn\n\n\t\t\tcase <-s.quitCh:\n\t\t\t\t// pipe.shutdown only covers entries still queued; this one is\n\t\t\t\t// ours to clean up.\n\t\t\t\tjsa.replies.Delete(ack.reply)\n\t\t\t\treturn\n\t\t\t}\n\n\t\tcase <-pipe.quitCh:\n\t\t\treturn\n","sourceCodeStart":4582,"sourceCodeEnd":4618,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/mqtt.go#L4582-L4618","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (server config)\nmqtt { js_timeout: \"5s\" }\n// after\nmqtt { js_timeout: \"30s\" }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"client.OnConnectionLost = func(_ mqtt.Client, err error) {\n  if strings.Contains(err.Error(), \"waiting for the JetStream ack\") {\n    log.Printf(\"JS ack timeout, backing off: %v\", err)\n    time.Sleep(backoff)\n    reconnectWithSessionResume()\n  }\n}","preventionTips":["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"],"tags":["mqtt","jetstream","ack-timeout","qos1"],"backgroundTag":"jetstream-ack-timeout","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}