hashicorp/nomad · error

failed to finalize snapshot: %v

Error message

failed to finalize snapshot: %v

What it means

This error wraps the failure of tar.Writer.Close() while finalizing the snapshot tar archive in helper/snapshot/archive.go write(). Close() flushes any buffered data and writes the tar end-of-archive blocks; if the underlying output writer (out io.Writer) returns an error there (e.g. disk full on a file sink, closed pipe, broken connection to storage), it is surfaced as 'failed to finalize snapshot'. All prior writes may have succeeded, so the failure is purely at archive-finalization/flush time on the destination writer.

Source

Thrown at helper/snapshot/archive.go:163

	var shaBuffer bytes.Buffer
	if err := hl.Encode(&shaBuffer); err != nil {
		return fmt.Errorf("failed to encode snapshot hashes: %v", err)
	}
	if err := archive.WriteHeader(&tar.Header{
		Name:    "SHA256SUMS",
		Mode:    0600,
		Size:    int64(shaBuffer.Len()),
		ModTime: now,
	}); err != nil {
		return fmt.Errorf("failed to write snapshot hashes header: %v", err)
	}
	if _, err := io.Copy(archive, &shaBuffer); err != nil {
		return fmt.Errorf("failed to write snapshot metadata: %v", err)
	}

	// Finalize the archive.
	if err := archive.Close(); err != nil {
		return fmt.Errorf("failed to finalize snapshot: %v", err)
	}

	return nil
}

// read takes a reader and extracts the snapshot metadata and the snapshot
// itself, and also checks the integrity of the data. You must arrange to call
// Close() on the returned object or else you will leak a temporary file.
func read(in io.Reader, metadata *raft.SnapshotMeta, snap io.Writer) error {
	// Start a new tar reader.
	archive := tar.NewReader(in)

	// Create a hash list that we will use to compare with the SHA256SUMS
	// file in the archive.
	hl := newHashList()

	// Populate the hashes for all the files we expect to see. The check at
	// the end will make sure these are all present in the SHA256SUMS file

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check free disk space / write permissions on the snapshot destination and retry after freeing space
  2. If streaming to a remote sink, verify the sink connection and retry the snapshot operation
  3. Inspect the wrapped %v error for the true underlying cause and fix that writer
  4. If writing to an HTTP response, ensure the client keeps the connection open for the full snapshot download

Example fix

// before
f, _ := os.Create(path)
snapshot.Store(f)
// after
f, err := os.Create(path)
if err != nil { return err }
defer f.Close()
if err := snapshot.Store(f); err != nil {
    return fmt.Errorf("snapshot write failed (check disk space/permissions on %s): %w", path, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go has no pre-call check, but validate the sink before writing:
info, err := os.Stat(targetDir)
if err != nil || !info.IsDir() {
    return fmt.Errorf("snapshot target dir invalid: %v", err)
}
// ensure writable
probe, err := os.CreateTemp(targetDir, "snap-probe-*")
if err != nil {
    return fmt.Errorf("snapshot target not writable: %v", err)
}
probe.Close()
os.Remove(probe.Name())

Type guard

// errors.As to inspect the underlying writer failure
func unwrapFinalizeErr(err error) error {
    if err != nil && strings.Contains(err.Error(), "failed to finalize snapshot") {
        var inner error
        if _, scan := fmt.Sscanf(err.Error(), "failed to finalize snapshot: %v", &inner); scan == nil {
            return inner
        }
    }
    return err
}

Try / catch

if err := snapshot.Store(out); err != nil {
    if strings.Contains(err.Error(), "failed to finalize snapshot") {
        log.Error("snapshot finalize failed (disk/network on destination)", "err", err)
        // free space / reset sink, then retry
        return retryStore()
    }
    return err
}

Prevention

When it happens

Trigger: Calling snapshot write()/Store.Store/TakeSnapshot where the destination io.Writer errors during Close: writing to a full disk, a closed or broken pipe (e.g. HTTP response writer closed client-side mid-snapshot), a network writer (S3/consul sink) timing out during flush, or an os.File whose write fails at the tail.

Common situations: Disk quota/full filesystem on the node storing the snapshot; client disconnects while downloading a snapshot via the Consul HTTP API; transient network failure to a remote snapshot sink; output file handle closed prematurely by surrounding code.

Related errors


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