nats-io/nats-server · error
failed to read consumer %q state: %w
Error message
failed to read consumer %q state: %w
What it means
Reading the body of a 'consumers/<name>' archive entry with io.ReadAll failed, so the consumer's snapshot state could not be loaded; the restore aborts with the consumer name in the message. As with 951, the raw I/O cause is not wrapped — the underlying reader error surfaced from the s2/tar stream.
Source
Thrown at server/stream_backup.go:422
if err = fmt.Errorf("failed to activate consumer %q: %w", o.name, err); retErr == nil {
retErr = err
}
s.Warnf("JetStream stream restore for '%s > %s' failed to activate consumers: %v", a.Name, cfg.Name, err)
}
}
}()
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)View on GitHub (pinned to 3a66a489d2)
Solutions
- Re-take or re-transfer the backup and verify checksums before restoring
- Remove proxy/upload size or timeout limits blocking large restore bodies, or restore the consumer state via direct file placement on the server
- Compare the archive size against the original snapshot; a mismatch confirms truncation — re-download
- If only one consumer entry is corrupt and consumers are dispensable, regenerate the snapshot without it (or use `nats stream backup --consumers=false`)
Defensive patterns
Strategy: validation
Validate before calling
if want, got := expectedChecksum, fileChecksum(snapshotPath); want != got {
return fmt.Errorf("snapshot corrupt/truncated; refusing restore")
} Try / catch
_, err := acc.RestoreStreamV2(cfg, r)
if err != nil {
if strings.Contains(err.Error(), "failed to read consumer") {
// archive unreadable mid-entry: re-transfer snapshot and retry
}
return err
} Prevention
- Checksum snapshots after transfer and before restore
- Let backups finish before copying; copy only closed files
- Raise proxy/body limits for large restore requests
- Use retries with resumable transfer for snapshots over unreliable networks
When it happens
Trigger: The compressed bytes for a consumer entry are truncated or corrupt: interrupted backup, partial file transfer, bit-flip corruption in the s2 stream, or a connection drop while streaming the restore request body to STREAM.RESTORE.
Common situations: Large backups transferred over flaky networks; snapshots copied with `cp` while the source backup was still being written; corrupted files on unreliable storage; restore requests aborted mid-stream by proxies with body-size/timeout limits.
Related errors
- flush of last block failed: %w
- expected state.json contents
- failed to activate consumer %q: %w
- expected consumer, found %q
- failed to decode consumer %q state: %w
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/30566e3351760660.
Report an issue: GitHub.