{"record":{"id":"f933d5f14d8e5459","repo":"nats-io/nats-server","slug":"unable-to-persist-session-q-seq-v-invalid-pub","errorCode":null,"errorMessage":"unable to persist session %q (seq=%v): invalid pub ack response","messagePattern":"unable to persist session %q \\(seq=(.+?)\\): invalid pub ack response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mqtt.go","lineNumber":3439,"sourceCode":"\t\tbb := bytes.Buffer{}\n\t\tbb.WriteString(hdrLine)\n\t\tbb.WriteString(JSExpectedLastSubjSeq)\n\t\tbb.WriteString(\":\")\n\t\tbb.WriteString(strconv.FormatInt(int64(seq), 10))\n\t\tbb.WriteString(CR_LF)\n\t\tbb.WriteString(CR_LF)\n\t\thdr = bb.Len()\n\t\tbb.Write(b)\n\t\tb = bb.Bytes()\n\t}\n\n\tresp, err := sess.jsa.storeSessionMsg(domainTk, cidHash, hdr, b)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to persist session %q (seq=%v): %v\", ps.ID, seq, err)\n\t}\n\t// Guard before dereferencing below.\n\tif resp == nil || resp.PubAck == nil {\n\t\treturn fmt.Errorf(\"unable to persist session %q (seq=%v): invalid pub ack response\", ps.ID, seq)\n\t}\n\tsess.mu.Lock()\n\tsess.seq = resp.Sequence\n\tsess.mu.Unlock()\n\treturn nil\n}\n\n// Clear the session.\n//\n// Runs from the client's readLoop.\n// Lock not held on entry, but session is in the locked map.\nfunc (sess *mqttSession) clear(noWait bool) error {\n\tvar durs []string\n\tvar pubRelDur string\n\n\tsess.mu.Lock()\n\tid := sess.id\n\tseq := sess.seq","sourceCodeStart":3421,"sourceCodeEnd":3457,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/mqtt.go#L3421-L3457","documentation":"Returned when the JetStream publish of the session record succeeds without error but the response is unusable: resp is nil or resp.PubAck is nil, so the new sequence cannot be confirmed. This is a defensive guard against an malformed/missing acknowledgement.","triggerScenarios":"storeSessionMsg returns resp == nil or resp.PubAck == nil despite err == nil — an unexpected/empty JetStream publish acknowledgement, typically from an API/transport anomaly or a bug in the async pub path.","commonSituations":"JetStream API returning malformed acks during instability; mixed server versions in a cluster; internal async-publish race.","solutions":["Retry the CONNECT / session persistence operation","Upgrade all servers to a consistent version (likely internal bug fixed upstream)","Check JetStream health and logs around the time of the failure","Report/inspect the wrapped scenario: err==nil but PubAck missing"],"exampleFix":"// before\n// err==nil, resp.PubAck==nil -> error\n// after\n// upgrade server binaries to matching versions and restart the cluster\nnull","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await mqttConnect()\n} catch (e) {\n  if (String(e).includes('invalid pub ack response')) {\n    log.error('JetStream returned malformed pub ack; check cluster version consistency', e)\n    await mqttConnect() // one retry\n  } else { throw e }\n}","preventionTips":["Keep all servers on the same binary version","Watch for JetStream API anomalies in server logs","Retry CONNECT once; persistent occurrences indicate a bug to report upstream","Maintain a support bundle (jsz, logs) when this occurs"],"tags":["mqtt","jetstream","ack"],"backgroundTag":"missing-puback-response","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}