{"record":{"id":"b10211388150c7cb","repo":"nats-io/nats-server","slug":"failed-to-decode-consumer-q-state-w","errorCode":null,"errorMessage":"failed to decode consumer %q state: %w","messagePattern":"failed to decode consumer %q state: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/stream_backup.go","lineNumber":426,"sourceCode":"\t\t\t}\n\t\t}\n\t}()\n\tfor range nstate.Consumers {\n\t\thdr, err := tr.Next()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tname, found := strings.CutPrefix(hdr.Name, \"consumers/\")\n\t\tif !found {\n\t\t\treturn nil, fmt.Errorf(\"expected consumer, found %q\", hdr.Name)\n\t\t}\n\t\tbuf, err := io.ReadAll(tr)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to read consumer %q state: %w\", name, err)\n\t\t}\n\t\tvar consumer SnapshotConsumerState\n\t\tif err := json.Unmarshal(buf, &consumer); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to decode consumer %q state: %w\", name, err)\n\t\t}\n\t\tif consumer.ConsumerConfig == nil {\n\t\t\treturn nil, fmt.Errorf(\"consumer %q is missing config\", name)\n\t\t}\n\t\tif consumer.ConsumerState == nil {\n\t\t\treturn nil, fmt.Errorf(\"consumer %q is missing state\", name)\n\t\t}\n\t\tisEphemeral := !isDurableConsumer(consumer.ConsumerConfig)\n\t\tif isEphemeral {\n\t\t\t// Keep ephemerals alive and interested until all messages have\n\t\t\t// been restored, then start their normal inactivity lifecycle.\n\t\t\tconsumer.Durable = name\n\t\t}\n\t\to, err := mset.addConsumerForRestore(consumer.ConsumerConfig)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to add consumer %q: %w\", name, err)\n\t\t}\n\t\tif isEphemeral {","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/stream_backup.go#L408-L444","documentation":"A consumer entry's bytes were read successfully but could not be decoded as JSON into SnapshotConsumerState; the json.Unmarshal error is wrapped via %w. The consumer state in the snapshot is syntactically broken or from an incompatible schema.","triggerScenarios":"json.Unmarshal(buf, &SnapshotConsumerState) fails: the consumer file inside the archive was hand-edited, produced by a different nats-server version with a changed consumer-state schema, or is a placeholder/garbage file placed at a consumers/<name> path by a custom pipeline.","commonSituations":"Manual edits to consumer state (deliver/ack floor sequences) introducing invalid JSON or wrong types; restoring snapshots across major version gaps; backup tooling that wrote non-JSON placeholders; file corruption localized to one entry.","solutions":["Read the wrapped JSON error to find the offending field and fix the consumer entry's JSON to match SnapshotConsumerState (ConsumerConfig + ConsumerState objects present)","Regenerate the snapshot from the source stream rather than hand-crafting consumer files","Align nats-server versions between the backup and restore hosts to eliminate schema drift","Validate offline: extract the consumers/<name> entry and run it through a JSON parser / unmarshal into SnapshotConsumerState before restoring"],"exampleFix":"// before: consumer entry missing required sections\n{\"Durable\": \"orders\"}\n// after: full SnapshotConsumerState shape\n{\"ConsumerConfig\": {\"Durable\": \"orders\", \"AckPolicy\": \"explicit\"}, \"ConsumerState\": {\"DeliveredConsumerSeq\": 1, \"AckFloorConsumerSeq\": 1}}","handlingStrategy":"validation","validationCode":"var cs SnapshotConsumerState\nif err := json.Unmarshal(rawConsumerJSON, &cs); err != nil {\n    return fmt.Errorf(\"consumer state invalid: %w\", err)\n}\nif cs.ConsumerConfig == nil || cs.ConsumerState == nil {\n    return fmt.Errorf(\"consumer entry missing config/state\")\n}","typeGuard":null,"tryCatchPattern":"_, err := acc.RestoreStreamV2(cfg, r)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to decode consumer\") {\n        // locate the offending consumers/<name> entry via the error and fix or drop it\n    }\n    return err\n}","preventionTips":["Don't hand-edit consumer snapshot files; regenerate snapshots instead","Validate each consumers/<name> entry unmarshals into SnapshotConsumerState before restore","Keep backup/restore nats-server versions aligned to avoid schema drift","Only include consumers/<name> JSON files in snapshot archives, never placeholders"],"tags":["jetstream","stream-restore","json","consumer","schema-validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}