hashicorp/packer · error

unable to create file %s: %s

Error message

unable to create file %s: %s

What it means

PostProcess-time failure in the checksum post-processor: after creating parent directories, it opens the checksum output file with os.OpenFile (O_WRONLY|O_APPEND|O_CREATE, 0644); failure (permission denied, path is a directory, disk full) aborts with keep=true. The path and wrapped OS error are included.

Source

Thrown at post-processor/checksum/post-processor.go:140

		h = getHash(ct)
		generatedData["ChecksumType"] = ct
		p.config.ctx.Data = generatedData

		for _, art := range files {
			checksumFile, err := interpolate.Render(p.config.OutputPath, &p.config.ctx)
			if err != nil {
				return nil, false, true, err
			}

			if _, err := os.Stat(checksumFile); err != nil {
				newartifact.files = append(newartifact.files, checksumFile)
			}
			if err := os.MkdirAll(filepath.Dir(checksumFile), os.FileMode(0755)); err != nil {
				return nil, false, true, fmt.Errorf("unable to create dir: %s", err.Error())
			}
			fw, err := os.OpenFile(checksumFile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(0644))
			if err != nil {
				return nil, false, true, fmt.Errorf("unable to create file %s: %s", checksumFile, err.Error())
			}
			fr, err := os.Open(art)
			if err != nil {
				fw.Close()
				return nil, false, true, fmt.Errorf("unable to open file %s: %s", art, err.Error())
			}

			if _, err = io.Copy(h, fr); err != nil {
				fr.Close()
				fw.Close()
				return nil, false, true, fmt.Errorf("unable to compute %s hash for %s", ct, art)
			}
			fr.Close()
			_, _ = fw.WriteString(fmt.Sprintf("%x\t%s\n", h.Sum(nil), filepath.Base(art)))
			fw.Close()
			h.Reset()
		}
	}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Make sure `output` resolves to a file path, not a directory, and doesn't collide with existing directories
  2. Grant write permission on the target directory to the user running Packer
  3. Free disk space / check inode usage on the target filesystem
  4. Choose a fresh output name (the file is opened in append mode, so consider removing stale checksum files first)

Example fix

// before
output = "out/{{.BuildName}}/"  // resolves to a directory
// after
output = "out/{{.BuildName}}.sha256.checksum"
Defensive patterns

Strategy: validation

Validate before calling

// shell: ensure the checksum output path is a writable file path
OUT="$(pwd)/out/packer.checksum"
test ! -d "$OUT" || { echo "$OUT is a directory"; exit 1; }
mkdir -p "$(dirname "$OUT")"
test -w "$(dirname "$OUT")" || { echo "dir not writable"; exit 1; }
df -h "$(dirname "$OUT")" | awk 'NR==2 {if ($5+0 >= 95) {print "disk nearly full"; exit 1}}'

Try / catch

artifact, _, _, err := pp.PostProcess(ctx, ui, art)
if err != nil {
    if strings.Contains(err.Error(), "unable to create file") {
        // fix path collision/permissions/space, then rerun
    }
    return err
}

Prevention

When it happens

Trigger: The rendered checksum file path cannot be opened for writing — e.g. output template resolves to an existing DIRECTORY (checksumFile collides with a directory name), the directory isn't writable by the Packer user, or the filesystem is out of space/inodes.

Common situations: Output path ending in "/" or resolving to a directory; prior build created a directory with the same name; running Packer as a non-root user against a root-owned directory; read-only volume or full disk in CI.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05). Data as JSON: /api/errors/baf63744c11a6c51. Report an issue: GitHub.