{"record":{"id":"12e9ebbb2f14d4e2","repo":"nats-io/nats-server","slug":"unmarshal-of-session-record-at-sequence-v-w","errorCode":null,"errorMessage":"unmarshal of session record at sequence %v: %w","messagePattern":"unmarshal of session record at sequence (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mqtt.go","lineNumber":3174,"sourceCode":"func (as *mqttAccountSessionManager) createOrRestoreSession(clientID string, opts *Options) (*mqttSession, bool, error) {\n\tjsa := &as.jsa\n\n\thash := getHash(clientID)\n\tsmsg, err := jsa.loadSessionMsg(as.domainTk, hash)\n\tif err != nil {\n\t\tif isErrorOtherThan(err, JSNoMessageFoundErr) {\n\t\t\treturn nil, false, fmt.Errorf(\"loading session record: %w\", err)\n\t\t}\n\t\t// Message not found, so reate the session...\n\t\t// Create a session and indicate that this session did not exist.\n\t\tsess := mqttSessionCreate(jsa, clientID, hash, 0, opts)\n\t\tsess.domainTk = as.domainTk\n\t\treturn sess, false, nil\n\t}\n\t// We need to recover the existing record now.\n\tps := &mqttPersistedSession{}\n\tif err := json.Unmarshal(smsg.Data, ps); err != nil {\n\t\treturn nil, false, fmt.Errorf(\"unmarshal of session record at sequence %v: %w\", smsg.Sequence, err)\n\t}\n\tif ps.ID != clientID {\n\t\treturn nil, false, errMQTTSessionCollision\n\t}\n\tfor sid, cc := range ps.Cons {\n\t\tif cc == nil {\n\t\t\tdelete(ps.Cons, sid)\n\t\t}\n\t}\n\n\t// Restore this session (even if we don't own it), the caller will do the right thing.\n\tsess := mqttSessionCreate(jsa, clientID, hash, smsg.Sequence, opts)\n\tsess.domainTk = as.domainTk\n\tsess.clean = ps.Clean\n\tsess.subs = ps.Subs\n\tsess.cons = ps.Cons\n\tsess.pubRelConsumer = ps.PubRel\n\tas.addSession(sess, true)","sourceCodeStart":3156,"sourceCodeEnd":3192,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/mqtt.go#L3156-L3192","documentation":"Wraps a json.Unmarshal failure when decoding a persisted mqttPersistedSession record read from JetStream. If the stored bytes cannot decode into mqttPersistedSession, the session cannot be recovered, so the server fails the CONNECT rather than silently corrupting state.","triggerScenarios":"The message stored in the '$MQTT.sess' stream at smsg.Sequence is not valid JSON for mqttPersistedSession — corrupted record, truncated write, wrong payload, or a record written by a different/incompatible format.","commonSituations":"Disk corruption or partial write on the JetStream filestore; manual edits/republishing into the internal $MQTT streams; version upgrade/downgrade with changed persistence format; garbage injected into internal streams.","solutions":["Delete the corrupted session record (or the whole session) so a fresh one is recreated on next CONNECT","Verify no external publishers are writing to internal $MQTT.* streams","Check server version compatibility of stored records (upgrade/downgrade)","Inspect underlying disk/filestore health for corruption"],"exampleFix":"// before\n// corrupted record at seq N blocks reconnect\n// after\nnats stream msg delete $MQTT.sess <seq>  // session recreated on next CONNECT\nnull","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await mqttConnect()\n} catch (e) {\n  if (String(e).includes('unmarshal of session record')) {\n    // discard the corrupted session by reconnecting with clean_session=true\n    await mqttConnect({ cleanSession: true })\n  } else { throw e }\n}","preventionTips":["Never let external publishers write to internal $MQTT.* streams","Keep all servers on the same version to avoid format mismatches","Monitor filestore/disk health to catch corruption early","Recover by clearing the session record and reconnecting with clean session"],"tags":["mqtt","json","persistence","corruption"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}