hashicorp/packer · error

failed to create destination directory for user SBOM: %s

Error message

failed to create destination directory for user SBOM: %s

What it means

If the configured destination path does not exist, getUserDestination derives its parent directory (filepath.Dir) and attempts to create the missing directory tree with os.MkdirAll(outDir, 0755). Failure (permission denied on an ancestor, read-only filesystem, path component is a file, invalid name) is wrapped and returned as this error, so SBOM writing aborts.

Source

Thrown at provisioner/hcp-sbom/provisioner.go:448

	if err == nil {
		if info.IsDir() {
			// If the destination is a directory, create a temporary file inside it
			tmpFile, err := os.CreateTemp(dst, "packer-user-sbom-*.json")
			if err != nil {
				return "", fmt.Errorf("failed to create temporary file in user SBOM directory %s: %s", dst, err)
			}
			dst = tmpFile.Name()
			_ = tmpFile.Close() // Ignore error on close after getting name
		}
		return dst, nil
	}

	outDir := filepath.Dir(dst)
	// In case the destination does not exist, we'll get the dirpath,
	// and create it if it doesn't already exist
	err = os.MkdirAll(outDir, 0755)
	if err != nil {
		return "", fmt.Errorf("failed to create destination directory for user SBOM: %s", err)
	}

	// Check if the destination is a directory after the previous step.
	//
	// This happens if the path specified ends with a `/`, in which case the
	// destination is a directory, and we must create a temporary file in
	// this destination directory.
	destStat, statErr := os.Stat(dst)
	if statErr == nil && destStat.IsDir() {
		tmpFile, err := os.CreateTemp(outDir, "packer-user-sbom-*.json")
		if err != nil {
			return "", fmt.Errorf("failed to create temporary file in user SBOM directory %s: %s", dst, err)
		}
		dst = tmpFile.Name()
		_ = tmpFile.Close() // Ignore error on close after getting name
	}

	return dst, nil

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Create the parent directory manually with correct ownership: `mkdir -p <parent> && chown $(id -u) <parent>`.
  2. Choose a destination under a writable path (project dir, $HOME, output_directory of the builder).
  3. If a path component is a file, remove/rename it so the directory can be created (`ls -l` each component of the path).
  4. If running in a container/CI, mount the output volume rw and confirm with `mount | grep <path>`.
  5. Check `ENOTDIR`/`EACCES` in the wrapped error message to distinguish not-a-directory from permission problems.

Example fix

// before
destination = "/opt/sbom-tool/out/sbom.json" // /opt/sbom-tool not creatable

// after
destination = "./out/sbom.json"
Defensive patterns

Strategy: validation

Validate before calling

// Validate ancestors of the destination before building:
dst="/opt/sbom-tool/out/sbom.json"
parent="$(dirname "$dst")"
if [ -e "$dst" ] && [ -f "$dst" ]; then echo "$dst exists as dir-parent? check"; fi
# ensure no component of $parent is a regular file and the nearest existing ancestor is writable
while [ ! -e "$parent" ]; do parent="$(dirname "$parent")"; done
[ -w "$parent" ] || { echo "$parent not writable"; exit 1; }

Try / catch

dst, err := p.getUserDestination()
if err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) && errors.Is(perr.Err, syscall.ENOTDIR) {
        return fmt.Errorf("a component of %s is a file, not a directory", perr.Path)
    }
    return err
}

Prevention

When it happens

Trigger: `destination` path does not exist and os.MkdirAll on its parent fails: an ancestor directory is not writable, a path component exists as a regular file (e.g. /out is a file, destination /out/sbom.json), or the filesystem is read-only.

Common situations: Destination like `/opt/mytool/sbom.json` where /opt/mytool cannot be created by the current user; destination under a path where an intermediate name is actually a file; running Packer inside a container whose target volume is mounted read-only; typo making the path land under a non-writable root (e.g. `/proot/...`).

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


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