{"record":{"id":"83fef55f731e6cc4","repo":"hashicorp/nomad","slug":"list-missing-hash-for-q","errorCode":null,"errorMessage":"list missing hash for %q","messagePattern":"list missing hash for %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/snapshot/archive.go","lineNumber":78,"sourceCode":"\treturn nil\n}\n\n// DecodeAndVerify reads a SHA256SUMS-style text file and checks the results\n// against the current sums for all the hashes.\nfunc (hl *hashList) DecodeAndVerify(r io.Reader) error {\n\t// Read the file and make sure everything in there has a matching hash.\n\tseen := make(map[string]struct{})\n\ts := bufio.NewScanner(r)\n\tfor s.Scan() {\n\t\tsha := make([]byte, sha256.Size)\n\t\tvar file string\n\t\tif _, err := fmt.Sscanf(s.Text(), \"%x  %s\", &sha, &file); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\th, ok := hl.hashes[file]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"list missing hash for %q\", file)\n\t\t}\n\t\tif !bytes.Equal(sha, h.Sum([]byte{})) {\n\t\t\treturn fmt.Errorf(\"hash check failed for %q\", file)\n\t\t}\n\t\tseen[file] = struct{}{}\n\t}\n\tif err := s.Err(); err != nil {\n\t\treturn err\n\t}\n\n\t// Make sure everything we had a hash for was seen.\n\tfor file := range hl.hashes {\n\t\tif _, ok := seen[file]; !ok {\n\t\t\treturn fmt.Errorf(\"file missing for %q\", file)\n\t\t}\n\t}\n\n\treturn nil","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/snapshot/archive.go#L60-L96","documentation":"DecodeAndVerify parses a SHA256SUMS-style manifest from a snapshot archive and checks each listed file's hash against hashes the reader has been accumulating via hashList.Add. This error means the manifest lists a file that the code never registered a hash for — the archive's SHA256SUMS references content that doesn't belong to the expected snapshot layout (meta.json, state.bin).","triggerScenarios":"Calling DecodeAndVerify (via read, when loading a snapshot archive) where the SHA256SUMS stream contains a line naming a file that was not passed to hl.Add — e.g. an archive with extra entries listed in SHA256SUMS, a manifest from a different archive, or a manifest tampered/replaced with foreign file names.","commonSituations":"Hand-edited or spliced snapshot tarballs; an archive produced by a different tool or Nomad version with extra files listed in SHA256SUMS; partially extracted/rebuilt archives where SHA256SUMS was kept but content files changed; corrupted download where the manifest survived but the expected file set differs.","solutions":["Take a fresh snapshot with `nomad snapshot save` and restore from that archive instead of the failing one.","Inspect the archive (`tar -tf <snap>` plus extracting SHA256SUMS) and compare listed files against the expected meta.json/state.bin set; discard archives with unexpected entries.","Verify the archive's integrity/provenance — if SHA256SUMS was edited or the archive spliced, do not trust it.","Re-download or re-copy the snapshot (checksum the transfer) if corruption during transfer is suspected.","If this happens on archives your own tooling produces, ensure every file written into the tar is registered with hashList.Add before Encode."],"exampleFix":"// before: verifying an untrusted/foreign manifest directly\nhl := newHashList()\nhl.Add(\"meta.json\"); hl.Add(\"state.bin\")\nerr := hl.DecodeAndVerify(sumsReader) // fails: unknown file in list\n// after: prefer a freshly taken snapshot archive\n// nomad snapshot save backup.snap\nerr := snapshot.LoadArchive(freshSnapshotFile)","handlingStrategy":"validation","validationCode":"// before decoding, sanity-check that the archive's manifest only\n// contains the expected files\ntr := tar.NewReader(f)\nfor {\n    hdr, err := tr.Next()\n    if err == io.EOF { break }\n    if err != nil { return err }\n    switch hdr.Name {\n    case \"meta.json\", \"state.bin\", \"SHA256SUMS\":\n    default:\n        return fmt.Errorf(\"unexpected file in snapshot archive: %s\", hdr.Name)\n    }\n}","typeGuard":null,"tryCatchPattern":"err := hl.DecodeAndVerify(r)\nif err != nil {\n    if strings.Contains(err.Error(), \"list missing hash for\") {\n        return fmt.Errorf(\"snapshot archive manifest references unknown files; archive is not a valid Nomad snapshot: %w\", err)\n    }\n    return err\n}","preventionTips":["Only restore snapshots produced by `nomad snapshot save`.","Never hand-edit or splice snapshot tarballs or SHA256SUMS.","Checksum snapshot files after transfer and before restoring.","When writing archives with hashList, register every file via Add before Encode."],"tags":["snapshot","integrity","sha256","archive"],"backgroundTag":"snapshot-checksum-mismatch","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"}