nats-io/nats-server · error
failed to decode consumer %q state: %w
Error message
failed to decode consumer %q state: %w
What it means
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.
Source
Thrown at server/stream_backup.go:426
}
}
}()
for range nstate.Consumers {
hdr, err := tr.Next()
if err != nil {
return nil, err
}
name, found := strings.CutPrefix(hdr.Name, "consumers/")
if !found {
return nil, fmt.Errorf("expected consumer, found %q", hdr.Name)
}
buf, err := io.ReadAll(tr)
if err != nil {
return nil, fmt.Errorf("failed to read consumer %q state: %w", name, err)
}
var consumer SnapshotConsumerState
if err := json.Unmarshal(buf, &consumer); err != nil {
return nil, fmt.Errorf("failed to decode consumer %q state: %w", name, err)
}
if consumer.ConsumerConfig == nil {
return nil, fmt.Errorf("consumer %q is missing config", name)
}
if consumer.ConsumerState == nil {
return nil, fmt.Errorf("consumer %q is missing state", name)
}
isEphemeral := !isDurableConsumer(consumer.ConsumerConfig)
if isEphemeral {
// Keep ephemerals alive and interested until all messages have
// been restored, then start their normal inactivity lifecycle.
consumer.Durable = name
}
o, err := mset.addConsumerForRestore(consumer.ConsumerConfig)
if err != nil {
return nil, fmt.Errorf("failed to add consumer %q: %w", name, err)
}
if isEphemeral {View on GitHub (pinned to 3a66a489d2)
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
Example fix
// before: consumer entry missing required sections
{"Durable": "orders"}
// after: full SnapshotConsumerState shape
{"ConsumerConfig": {"Durable": "orders", "AckPolicy": "explicit"}, "ConsumerState": {"DeliveredConsumerSeq": 1, "AckFloorConsumerSeq": 1}} Defensive patterns
Strategy: validation
Validate before calling
var cs SnapshotConsumerState
if err := json.Unmarshal(rawConsumerJSON, &cs); err != nil {
return fmt.Errorf("consumer state invalid: %w", err)
}
if cs.ConsumerConfig == nil || cs.ConsumerState == nil {
return fmt.Errorf("consumer entry missing config/state")
} Try / catch
_, err := acc.RestoreStreamV2(cfg, r)
if err != nil {
if strings.Contains(err.Error(), "failed to decode consumer") {
// locate the offending consumers/<name> entry via the error and fix or drop it
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- error in state.json: %w
- failed to activate consumer %q: %w
- expected consumer, found %q
- failed to read consumer %q state: %w
- max_request_batch must be set if it's JetStream limits are s
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/b10211388150c7cb.
Report an issue: GitHub.