hashicorp/nomad · error

failed to create temp snapshot file: %v

Error message

failed to create temp snapshot file: %v

What it means

Restore() streams a snapshot archive into Raft without buffering it in memory, so it first creates a scratch temp file via os.CreateTemp. This error wraps any failure from that temp file creation, with the underlying os error appended. It indicates the process could not obtain a temporary file, usually an OS/environment problem rather than corrupted snapshot data.

Source

Thrown at helper/snapshot/snapshot.go:269

// Restore takes the snapshot from the reader and attempts to apply it to the
// given Raft instance.
func Restore(logger hclog.Logger, in io.Reader, r *raft.Raft) error {
	// Wrap the reader in a gzip decompressor.
	decomp, err := gzip.NewReader(&readWrapper{in, 0})
	if err != nil {
		return fmt.Errorf("failed to decompress snapshot: %v", err)
	}
	defer func() {
		if err := decomp.Close(); err != nil {
			logger.Error("Failed to close snapshot decompressor", "error", err)
		}
	}()

	// Make a scratch file to receive the contents of the snapshot data so
	// we can avoid buffering in memory.
	snap, err := os.CreateTemp("", "snapshot")
	if err != nil {
		return fmt.Errorf("failed to create temp snapshot file: %v", err)
	}
	defer func() {
		if err := snap.Close(); err != nil {
			logger.Error("Failed to close temp snapshot", "error", err)
		}
		if err := os.Remove(snap.Name()); err != nil {
			logger.Error("Failed to clean up temp snapshot", "error", err)
		}
	}()

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

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

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check the wrapped %v cause: verify the temp directory exists, is writable, and has free space (df, ls -ld $TMPDIR).
  2. Set TMPDIR (or os.TempDir behavior) to a writable path before running the process.
  3. Check filesystem quotas and mount flags (read-only, noexec) on the temp volume.
  4. Run the process as a user with permission to create files in the temp directory.

Example fix

// before (unwritable default temp dir)
snap, err := os.CreateTemp("", "snapshot") // fails: open /tmp/snapshot...: read-only file system
// after
// launch with a writable temp dir, e.g. in the service unit/container:
// Environment=TMPDIR=/var/lib/myapp/tmp   (and ensure the dir exists and is writable)
Defensive patterns

Strategy: validation

Validate before calling

tmp := os.TempDir()
if fi, err := os.Stat(tmp); err != nil || !fi.IsDir() {
    return fmt.Errorf("temp dir %s unavailable: %w", tmp, err)
}
probe, err := os.CreateTemp(tmp, "snapshot-probe")
if err != nil { return fmt.Errorf("cannot write temp files: %w", err) }
probe.Close(); os.Remove(probe.Name())

Prevention

When it happens

Trigger: Calling Restore (via snapshotRestore) when os.CreateTemp("", "snapshot") fails — e.g. the default temp directory (TMPDIR/tmp) does not exist, is not writable, the disk is full, or the process lacks permission to create files there.

Common situations: Containers launched with a read-only or unwritable /tmp; TMPDIR pointing at a nonexistent directory; disk-quota exhaustion on the node; running under a hardened security profile (noexec/no-temp files) or a stripped-down container image missing /tmp.

Related errors


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