hashicorp/nomad · error

list missing hash for %q

Error message

list missing hash for %q

What it means

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).

Source

Thrown at helper/snapshot/archive.go:78

	return nil
}

// DecodeAndVerify reads a SHA256SUMS-style text file and checks the results
// against the current sums for all the hashes.
func (hl *hashList) DecodeAndVerify(r io.Reader) error {
	// Read the file and make sure everything in there has a matching hash.
	seen := make(map[string]struct{})
	s := bufio.NewScanner(r)
	for s.Scan() {
		sha := make([]byte, sha256.Size)
		var file string
		if _, err := fmt.Sscanf(s.Text(), "%x  %s", &sha, &file); err != nil {
			return err
		}

		h, ok := hl.hashes[file]
		if !ok {
			return fmt.Errorf("list missing hash for %q", file)
		}
		if !bytes.Equal(sha, h.Sum([]byte{})) {
			return fmt.Errorf("hash check failed for %q", file)
		}
		seen[file] = struct{}{}
	}
	if err := s.Err(); err != nil {
		return err
	}

	// Make sure everything we had a hash for was seen.
	for file := range hl.hashes {
		if _, ok := seen[file]; !ok {
			return fmt.Errorf("file missing for %q", file)
		}
	}

	return nil

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Take a fresh snapshot with `nomad snapshot save` and restore from that archive instead of the failing one.
  2. 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.
  3. Verify the archive's integrity/provenance — if SHA256SUMS was edited or the archive spliced, do not trust it.
  4. Re-download or re-copy the snapshot (checksum the transfer) if corruption during transfer is suspected.
  5. If this happens on archives your own tooling produces, ensure every file written into the tar is registered with hashList.Add before Encode.

Example fix

// before: verifying an untrusted/foreign manifest directly
hl := newHashList()
hl.Add("meta.json"); hl.Add("state.bin")
err := hl.DecodeAndVerify(sumsReader) // fails: unknown file in list
// after: prefer a freshly taken snapshot archive
// nomad snapshot save backup.snap
err := snapshot.LoadArchive(freshSnapshotFile)
Defensive patterns

Strategy: validation

Validate before calling

// before decoding, sanity-check that the archive's manifest only
// contains the expected files
tr := tar.NewReader(f)
for {
    hdr, err := tr.Next()
    if err == io.EOF { break }
    if err != nil { return err }
    switch hdr.Name {
    case "meta.json", "state.bin", "SHA256SUMS":
    default:
        return fmt.Errorf("unexpected file in snapshot archive: %s", hdr.Name)
    }
}

Try / catch

err := hl.DecodeAndVerify(r)
if err != nil {
    if strings.Contains(err.Error(), "list missing hash for") {
        return fmt.Errorf("snapshot archive manifest references unknown files; archive is not a valid Nomad snapshot: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/83fef55f731e6cc4. Report an issue: GitHub.