{"record":{"id":"0dda17e549257be7","repo":"hashicorp/nomad","slug":"failed-to-read-snapshot-w-0dda17","errorCode":null,"errorMessage":"failed to read snapshot: %w","messagePattern":"failed to read snapshot: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/raftutil/snapshot.go","lineNumber":36,"sourceCode":"\nfunc RestoreFromArchive(archive io.Reader, filter *nomad.FSMFilter) (raft.FSM, *state.StateStore, *raft.SnapshotMeta, error) {\n\tlogger := hclog.L()\n\n\tfsm, err := dummyFSM(logger)\n\tif err != nil {\n\t\treturn nil, nil, nil, fmt.Errorf(\"failed to create FSM: %w\", err)\n\t}\n\n\t// r is closed by RestoreFiltered, w is closed by CopySnapshot\n\tr, w := io.Pipe()\n\n\terrCh := make(chan error)\n\tmetaCh := make(chan *raft.SnapshotMeta)\n\n\tgo func() {\n\t\tmeta, err := snapshot.CopySnapshot(archive, w)\n\t\tif err != nil {\n\t\t\terrCh <- fmt.Errorf(\"failed to read snapshot: %w\", err)\n\t\t} else {\n\t\t\tmetaCh <- meta\n\t\t}\n\t}()\n\n\terr = fsm.RestoreWithFilter(r, filter)\n\tif err != nil {\n\t\treturn nil, nil, nil, fmt.Errorf(\"failed to restore from snapshot: %w\", err)\n\t}\n\n\tselect {\n\tcase err := <-errCh:\n\t\treturn nil, nil, nil, err\n\tcase meta := <-metaCh:\n\t\treturn fsm, fsm.State(), meta, nil\n\t}\n}\n","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/raftutil/snapshot.go#L18-L54","documentation":"Inside RestoreFromArchive a goroutine runs snapshot.CopySnapshot(archive, w) to copy the snapshot archive into the pipe feeding the FSM restore. If CopySnapshot fails — the archive is not a valid Nomad snapshot, is truncated, or the pipe write fails because the FSM restore side closed early — the goroutine reports \"failed to read snapshot: %w\".","triggerScenarios":"The io.Reader passed to RestoreFromArchive is not a valid snapshot archive (corrupt tar/gzip, wrong file, empty stream), or the FSM's RestoreWithFilter aborts and closes the read end of the pipe, causing CopySnapshot's write to fail with a broken pipe.","commonSituations":"Passing a truncated download or an unrelated file to the nomad-snapshot tool; a corrupted snapshot on disk; a snapshot from an incompatible Nomad version that fails mid-copy; the restore side erroring first so the copy side surfaces a broken-pipe error.","solutions":["Verify the archive is a complete, valid Nomad snapshot: check its size and, if possible, validate it (e.g. `nomad operator snapshot inspect <file>`).","Re-take or re-download the snapshot; a truncated transfer is the most common cause.","Check the wrapped error: if it is 'broken pipe' or 'io: read/write on closed pipe', the real failure is on the restore side (see the companion 'failed to restore from snapshot' error) — fix that cause.","Ensure the snapshot was produced by a compatible Nomad version; upgrade the tool if the snapshot is newer."],"exampleFix":"// before: feeding a truncated file\nf, _ := os.Open(\"snapshot.tar\") // partially downloaded\nfsm, _, _, err := raftutil.RestoreFromArchive(f, nil) // \"failed to read snapshot: unexpected EOF\"\n// after: verify integrity first\nif fi, _ := f.Stat(); fi.Size() == 0 { return fmt.Errorf(\"empty snapshot file\") }\nout, err := exec.Command(\"nomad\", \"operator\", \"snapshot\", \"inspect\", path).CombinedOutput()\nif err != nil { return fmt.Errorf(\"invalid snapshot: %s\", out) }","handlingStrategy":"validation","validationCode":"// Validate the archive before feeding it to RestoreFromArchive\nfi, err := os.Stat(path)\nif err != nil || fi.Size() == 0 {\n    return fmt.Errorf(\"snapshot file missing or empty\")\n}\nif out, err := exec.Command(\"nomad\", \"operator\", \"snapshot\", \"inspect\", path).CombinedOutput(); err != nil {\n    return fmt.Errorf(\"invalid snapshot archive: %s\", out)\n}","typeGuard":null,"tryCatchPattern":"fsm, store, meta, err := raftutil.RestoreFromArchive(archive, filter)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to read snapshot\") {\n        if strings.Contains(err.Error(), \"closed pipe\") {\n            return fmt.Errorf(\"restore side failed first; check 'failed to restore from snapshot' cause\")\n        }\n        return fmt.Errorf(\"corrupt/truncated archive: %w\", err)\n    }\n    return err\n}","preventionTips":["Verify snapshots with `nomad operator snapshot inspect` before restoring.","Checksum downloaded snapshots against the value reported by `nomad operator snapshot save`.","Avoid restoring across Nomad major/minor versions the snapshot format doesn't support.","Never edit or re-compress the archive manually; keep it byte-identical to the original."],"tags":["snapshot","io","corruption"],"backgroundTag":"invalid-snapshot-archive","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}