{"record":{"id":"007187bb6c7290d4","repo":"hashicorp/nomad","slug":"failed-to-restore-from-snapshot-w","errorCode":null,"errorMessage":"failed to restore from snapshot: %w","messagePattern":"failed to restore from snapshot: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/raftutil/snapshot.go","lineNumber":44,"sourceCode":"\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\nfunc RedactSnapshot(srcFile *os.File) error {\n\tsrcFile.Seek(0, 0)\n\tfsm, store, meta, err := RestoreFromArchive(srcFile, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to load snapshot from archive: %w\", err)\n\t}\n\n\titer, err := store.RootKeys(nil)","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/raftutil/snapshot.go#L26-L62","documentation":"After piping the snapshot archive in, RestoreFromArchive calls fsm.RestoreWithFilter to stream the snapshot into the dummy FSM's state store. Any error from that restore (bad snapshot format, unsupported/unknown message types, decoding failures, filter errors) is wrapped as \"failed to restore from snapshot: %w\".","triggerScenarios":"RestoreWithFilter fails while consuming the piped snapshot: malformed archive contents, snapshot entries that fail to decode into the current FSM schema, an FSMFilter rejecting an entry, or the copy goroutine dying and closing the pipe mid-stream.","commonSituations":"Restoring a snapshot from a newer Nomad version into an older binary (unknown schemas/IMPL versions); a corrupted snapshot; a non-nil FSMFilter that rejects required entries; RedactSnapshot or NewHarnessFromSnapshot operating on an incompatible archive.","solutions":["Read the wrapped cause: decoding/unknown-type errors usually mean a Nomad version mismatch — upgrade the tool/binary to at least the version that wrote the snapshot.","Validate the archive with `nomad operator snapshot inspect` to rule out corruption.","If using a custom FSMFilter, check its logic — a filtering bug can make restore fail; try RestoreFromArchive with filter=nil to isolate.","Re-take the snapshot from a healthy leader if the archive is corrupt."],"exampleFix":"// before: restoring a v1.5 snapshot with a v1.4 binary\nfsm, _, _, err := raftutil.RestoreFromArchive(f, nil) // \"failed to restore from snapshot: ... unknown message type\"\n// after: use a binary >= snapshot version\n// (upgrade tooling) then:\nfsm, _, _, err := raftutil.RestoreFromArchive(f, nil) // succeeds","handlingStrategy":"try-catch","validationCode":"// Check version compatibility before attempting restore\n// snapshot meta (raft.SnapshotMeta) is only available after restore, so pre-validate with CLI:\nif out, err := exec.Command(\"nomad\", \"operator\", \"snapshot\", \"inspect\", path).CombinedOutput(); err != nil {\n    return fmt.Errorf(\"snapshot not compatible with this binary: %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 restore from snapshot\") {\n        // decoding/unknown-type failures usually mean version skew: retry with a newer binary\n        return fmt.Errorf(\"restore rejected archive (check Nomad version skew / FSMFilter): %w\", err)\n    }\n    return err\n}","preventionTips":["Run restores with a binary at or above the version that wrote the snapshot.","Test restores with filter=nil first to isolate FSMFilter-related failures.","Practice restores on a staging copy of the snapshot before touching production data.","Keep snapshot archives from each cluster tagged with the producing Nomad version."],"tags":["snapshot","fsm","restore","version-compatibility"],"backgroundTag":"snapshot-restore-failed","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"}