{"record":{"id":"473307174e277fca","repo":"nats-io/nats-server","slug":"invalid-stream-update-response-missing-stream-inf","errorCode":null,"errorMessage":"invalid stream update response: missing stream info","messagePattern":"invalid stream update response: missing stream info","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mqtt.go","lineNumber":1851,"sourceCode":"\t}\n\treturn scr.StreamInfo, scr.DidCreate, nil\n}\n\nfunc (jsa *mqttJSA) updateStream(cfg *StreamConfig) (*StreamInfo, error) {\n\tcfgb, err := json.Marshal(cfg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tscri, err := jsa.newRequest(mqttJSAStreamUpdate, fmt.Sprintf(JSApiStreamUpdateT, cfg.Name), 0, cfgb)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tscr := scri.(*JSApiStreamUpdateResponse)\n\tif err = scr.ToError(); err != nil {\n\t\treturn nil, err\n\t}\n\tif scr.StreamInfo == nil {\n\t\treturn nil, fmt.Errorf(\"invalid stream update response: missing stream info\")\n\t}\n\treturn scr.StreamInfo, nil\n}\n\nfunc (jsa *mqttJSA) lookupStream(name string) (*StreamInfo, error) {\n\tslri, err := jsa.newRequest(mqttJSAStreamLookup, fmt.Sprintf(JSApiStreamInfoT, name), 0, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tslr := slri.(*JSApiStreamInfoResponse)\n\tif err = slr.ToError(); err != nil {\n\t\treturn nil, err\n\t}\n\tif slr.StreamInfo == nil {\n\t\treturn nil, NewJSStreamNotFoundError()\n\t}\n\treturn slr.StreamInfo, nil\n}","sourceCodeStart":1833,"sourceCodeEnd":1869,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/mqtt.go#L1833-L1869","documentation":"Same class as the create variant but for stream updates: the JSApiStreamUpdateResponse came back without an error but also without StreamInfo, which the server requires to continue (it keeps the updated si). The response is treated as invalid.","triggerScenarios":"JS API stream update succeeded per ToError but response carried no StreamInfo — protocol/shape mismatch between server versions, malformed internal response, or an interceptor mangling $JS.API.STREAM.UPDATE replies.","commonSituations":"Rolling upgrades with mixed versions issuing internal stream updates (e.g. the MQTT retained stream MaxMsgsPer migration); corrupted responses under load.","solutions":["Align all cluster nodes to the same NATS Server version before running MQTT workloads","Retry the MQTT session setup; the update will be re-attempted","Verify nothing intercepts internal $JS.API subjects (no mirroring/leaf-node rewrite of JS API)","Capture debug logs and report upstream if it reproduces consistently"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Verify stream updates round-trip correctly before MQTT migration:\njs, _ := nc.JetStream()\nsi, err := js.UpdateStream(&nats.StreamConfig{Name: \"smoke-test\", Subjects: []string{\"x\"}})\nif err != nil || si == nil { /* JS update path broken */ }","typeGuard":"func hasStreamInfoUpd(scr *JSApiStreamUpdateResponse) bool { return scr != nil && scr.StreamInfo != nil }","tryCatchPattern":"if strings.Contains(err.Error(), \"invalid stream update response\") {\n    // retry; if persistent, check mixed-version cluster before further updates\n    return retryOnceElseCheckVersions(op)\n}","preventionTips":["Schedule version upgrades so no stream updates happen during mixed-version windows","Test stream update migrations in staging with same versions as production","Report persistent occurrences upstream with debug logs"],"tags":["jetstream","mqtt","protocol","invalid-response","stream-update"],"backgroundTag":"invalid-api-response","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}