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 errView on GitHub (pinned to 482b49bf1a)
Solutions
- Compare the received file size/checksum against the source snapshot's checksum header to confirm truncation.
- Re-transfer or re-create the snapshot from a healthy leader/node.
- Check the wrapped %v cause: if it's a dest write error, free space/fix permissions on the destination.
- 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
- Compare received size/checksum against the source before use.
- Re-transfer on any checksum mismatch instead of forcing restore.
- Keep the dest WriteCloser healthy (space, permissions) — its write errors surface here.
- Run Verify on candidate snapshots before any restore workflow.
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
- failed to read snapshot: %w
- failed to read snapshot hashes: %v
- failed to decompress snapshot: %v
- failed to read snapshot: %w
- Failed to copy snapshot to temporary file: %v
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/1d120a4c4f86d758.
Report an issue: GitHub.