nats-io/nats-server · warning
JetStream did not acknowledge the QoS1 message within %v (se
Error message
JetStream did not acknowledge the QoS1 message within %v (server is shutting down); failing the connection, the client will re-send unacknowledged PUBLISH packets on reconnect
What it means
During server shutdown, the JetStream subscriber for MQTT QoS1 acks stops waiting: when the per-ack timer expires while the server is terminating, it fails the pending ack with this verbose error and the client connection is failed. The message tells the operator the client will recover by resending unacknowledged PUBLISH packets after reconnecting.
Source
Thrown at server/mqtt.go:4685
pipe := c.mqtt.acks
if pipe == nil {
if pipe = s.mqttPipelineStart(c, jsa); pipe == nil {
// Server is shutting down, complete synchronously.
t := time.NewTimer(jsa.timeout)
defer t.Stop()
select {
case err := <-ack.done:
if err != nil {
return err
}
c.mu.Lock()
trace := c.trace
c.mu.Unlock()
c.mqttEnqueuePubResponse(mqttPacketPubAck, ack.pi, trace)
return nil
case <-t.C:
jsa.replies.Delete(ack.reply)
return fmt.Errorf("JetStream did not acknowledge the QoS1 message within %v "+
"(server is shutting down); failing the connection, "+
"the client will re-send unacknowledged PUBLISH packets on reconnect", jsa.timeout)
case <-s.quitCh:
// The reply may never come; do not hold up the shutdown.
jsa.replies.Delete(ack.reply)
return ErrServerNotRunning
}
}
c.mqtt.acks = pipe
}
return pipe.push(ack)
}
// Admits an entry into the pipeline. Rejects it once the pipeline is
// stopped: an entry admitted after the connection-close drain
// (mqttHandleClosedClient -> pipe.shutdown) would strand its reply
// registration in the account-scoped jsa.replies. readLoop only.View on GitHub (pinned to 3a66a489d2)
Solutions
- This is expected behavior during shutdown; ensure clients use clean-session=false and QoS1 so they re-send unacked PUBLISH on reconnect
- Drain MQTT traffic before shutdown (stop publishers, wait for in-flight acks) to avoid the error
- Reduce JS ack latency (storage tuning, quorum health) so acks complete before shutdown completes
- Use nats-server's graceful shutdown wait time long enough for in-flight acks to settle
Defensive patterns
Strategy: retry
Try / catch
client.OnConnectionLost = func(_ mqtt.Client, err error) {
if strings.Contains(err.Error(), "server is shutting down") {
scheduleReconnectWithBackoff() // client resends unacked QoS1 PUBLISH automatically
}
} Prevention
- Run MQTT clients with clean-session=false and manual-ack semantics so unacked QoS1 messages are resent
- Drain/stop publishers before planned server restarts
- Give the server a generous graceful shutdown wait period
- Retry reconnect with exponential backoff during rolling deployments
When it happens
Trigger: A QoS1 PUBLISH is pending a JetStream ack and the server's quitCh fires; the ack timer then expires before JetStream responds, producing this shutdown-path error instead of the normal timeout message.
Common situations: Rolling restarts or graceful shutdown with in-flight QoS1 MQTT traffic, long JS ack latency coinciding with shutdown, operators draining a cluster with connected MQTT publishers.
Related errors
- timeout after %v waiting for the JetStream ack
- QoS1 in-flight window is full (%d messages) and JetStream ha
- server is not running
- shutting down
- ack wait must be a positive value
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/327ce249c6602b7d.
Report an issue: GitHub.