hashicorp/nomad · error

failed to read snapshot file: %v

Error message

failed to read snapshot file: %v

What it means

CopySnapshot wraps errors from read(), which parses the raft.SnapshotMeta header and streams the (discarded) snapshot payload into dest. This means the gzip stream opened fine, but the archive inside is truncated, corrupt, or otherwise unreadable.

Source

Thrown at helper/snapshot/snapshot.go:212

	return CopySnapshot(in, Discard{Writer: io.Discard})
}

// CopySnapshot copies the snapshot content from snapshot archive to dest.
// It will close the destination once complete.
func CopySnapshot(in io.Reader, dest io.WriteCloser) (*raft.SnapshotMeta, error) {
	defer dest.Close()

	// Wrap the reader in a gzip decompressor.
	decomp, err := gzip.NewReader(in)
	if err != nil {
		return nil, fmt.Errorf("failed to decompress snapshot: %v", err)
	}
	defer decomp.Close()

	// Read the archive, throwing away the snapshot data.
	var metadata raft.SnapshotMeta
	if err := read(decomp, &metadata, dest); err != nil {
		return nil, fmt.Errorf("failed to read snapshot file: %v", err)
	}

	if err := concludeGzipRead(decomp); err != nil {
		return nil, err
	}

	return &metadata, nil
}

// concludeGzipRead should be invoked after you think you've consumed all of
// the data from the gzip stream. It will error if the stream was corrupt.
//
// The docs for gzip.Reader say: "Clients should treat data returned by Read as
// tentative until they receive the io.EOF marking the end of the data."
func concludeGzipRead(decomp *gzip.Reader) error {
	extra, err := io.ReadAll(decomp) // ReadAll consumes the EOF
	if err != nil {
		return err

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Compare the received file size/checksum against the source snapshot's checksum header to confirm truncation.
  2. Re-transfer or re-create the snapshot from a healthy leader/node.
  3. Check the wrapped %v cause: if it's a dest write error, free space/fix permissions on the destination.
  4. Run Verify against the candidate snapshot before attempting a restore to catch corruption early.
Defensive patterns

Strategy: try-catch

Validate before calling

// verify integrity first; Verify uses CopySnapshot and will surface the same corruption
if err := snapshot.Verify(in); err != nil {
	return fmt.Errorf("snapshot invalid, refusing to use: %w", err)
}

Try / catch

meta, err := CopySnapshot(in, dest)
if err != nil && strings.Contains(err.Error(), "failed to read snapshot file") {
	return fmt.Errorf("snapshot archive corrupt or truncated: %w", err)
}

Prevention

When it happens

Trigger: CopySnapshot/Verify where read(decomp, &metadata, dest) fails: truncated snapshot archive, corrupt msgpack header, dest write errors while draining payload, or mid-stream gzip corruption (CRC/length mismatch).

Common situations: Snapshot files damaged by interrupted transfers or failing storage; byte offsets shifted by manual edits; dest WriteCloser failing (disk full on the receiving side) during the copy.

Related errors


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