{"record":{"id":"7354a575ba04f335","repo":"nats-io/nats-server","slug":"expected-state-json-contents","errorCode":null,"errorMessage":"expected state.json contents","messagePattern":"expected state\\.json contents","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/stream_backup.go","lineNumber":264,"sourceCode":"\n// RestoreStreamSnapshotV2 will restore a stream from a snapshot.\nfunc (a *Account) RestoreStreamV2(ncfg *StreamConfig, r io.Reader) (retMset *stream, retErr error) {\n\tdec := s2.NewReader(r)\n\ttr := archive.NewReader(dec)\n\n\tvar nstate StreamState\n\n\t// Load the stream state.\n\thdr, err := tr.Next()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif hdr.Name != \"state.json\" {\n\t\treturn nil, fmt.Errorf(\"expected state.json first\")\n\t}\n\tstate, err := io.ReadAll(tr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"expected state.json contents\")\n\t}\n\tif err := json.Unmarshal(state, &nstate); err != nil {\n\t\treturn nil, fmt.Errorf(\"error in state.json: %w\", err)\n\t}\n\n\ts, jsa, err := a.checkForJetStream()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tjs := jsa.js\n\tif js == nil {\n\t\treturn nil, NewJSNotEnabledForAccountError()\n\t}\n\tif _, err := a.lookupStream(ncfg.Name); err == nil {\n\t\treturn nil, NewJSStreamNameExistRestoreFailedError()\n\t}\n\n\tcfg, apiErr := s.checkStreamCfg(ncfg, a, false)","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/stream_backup.go#L246-L282","documentation":"After confirming the first archive entry is named 'state.json', RestoreStreamV2 reads its full contents with io.ReadAll. If that read fails (underlying s2/tar reader error, e.g. corrupt compressed data or truncated stream), the restore is aborted with this message. Note the error text is a static string; the underlying read error is not wrapped.","triggerScenarios":"The s2-compressed archive data for the state.json entry is truncated mid-read — a partially downloaded/copied snapshot, a backup interrupted before completion (missing the end-of-backup sentinel), or disk/network I/O failure while the server reads the request body during STREAM.RESTORE.","commonSituations":"Snapshot file cut off by a failed upload over the NATS connection; an s2 file corrupted in transit; a backup taken while the source server was shutting down; restoring over an unreliable network where the restore chunk stream breaks early.","solutions":["Re-take the stream backup and verify it completes (snapshot ends with the end-of-backup sentinel)","Check the snapshot file size/checksum against the source to detect truncation before restoring","Restore over a stable connection; for large streams prefer server-side copy or file-based transport","If the file is intact, inspect server logs for the underlying s2/tar read error (I/O, disk) and fix the storage/transport issue"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fi, err := os.Stat(snapshotPath)\nif err != nil || fi.Size() == 0 {\n    return fmt.Errorf(\"snapshot missing or empty: %s\", snapshotPath)\n}\nif want, got := expectedChecksum, fileChecksum(snapshotPath); want != got {\n    return fmt.Errorf(\"snapshot truncated: got %d bytes\", got)\n}","typeGuard":null,"tryCatchPattern":"mset, err := acc.RestoreStreamV2(cfg, r)\nif err != nil {\n    if strings.Contains(err.Error(), \"expected state.json contents\") {\n        // archive read failed mid-entry: treat snapshot as corrupt, re-transfer\n    }\n    return err\n}","preventionTips":["Verify snapshot checksums after every transfer","Ensure backups complete (look for the end-of-backup sentinel) before moving files","Restore over reliable connections; avoid proxies with small body limits","Never restore from files still being written"],"tags":["jetstream","stream-restore","io-error"],"backgroundTag":"truncated-backup-file","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}