hashicorp/packer · error
unable to create dir: %s
Error message
unable to create dir: %s
What it means
PostProcess-time failure in the checksum post-processor: before writing each checksum file it ensures the parent directory exists with os.MkdirAll; if that fails (permission denied, path is a file, read-only volume) the whole post-process aborts with keep=true. The wrapped OS error details the cause.
Source
Thrown at post-processor/checksum/post-processor.go:136
newartifact := NewArtifact(artifact.Files())
for _, ct := range p.config.ChecksumTypes {
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)))View on GitHub (pinned to eb36e3c3e4)
Solutions
- Set `output` to a path under a writable directory you control (relative paths resolve under the working/output directory)
- Check ownership/permissions of the target's parent and pre-create the directory yourself
- Ensure no file exists at a path component where a directory is required
- Verify mount flags / security policies if running in a container
Example fix
// before
output = "/usr/local/share/packer/{{.BuildName}}.checksum"
// after
output = "out/{{.BuildName}}.checksum" Defensive patterns
Strategy: validation
Validate before calling
// shell: pre-flight check that the output directory is creatable/writable
OUT="$(pwd)/out"
mkdir -p "$OUT" || { echo "cannot create $OUT"; exit 1; }
test -w "$OUT" || { echo "$OUT not writable"; exit 1; }
# also ensure no file occupies a path component:
while [ -f "$(dirname "$OUT")" ]; do echo "conflict"; exit 1; done Try / catch
artifact, _, _, err := pp.PostProcess(ctx, ui, art)
if err != nil {
if strings.Contains(err.Error(), "unable to create dir") {
// fix permissions / path collision, rerun
}
return err
} Prevention
- Keep `output` under a directory the Packer user owns
- Avoid absolute paths into system directories (/etc, /usr)
- Pre-create and chmod the output directory in CI before the build
- Check for existing files that collide with required directory components
- Account for SELinux/AppArmor and read-only mounts in containers
When it happens
Trigger: The rendered output template resolves to a directory that cannot be created, e.g. output = "/etc/packer/out.checksum" (no permission), output under a read-only mount, or a path component exists as a regular file so MkdirAll returns ENOTDIR.
Common situations: Absolute paths pointing into protected system directories; output on a read-only container volume; existing FILE conflicting with an intended directory in the path; SELinux/AppArmor denials.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
Related errors
- unable to create file %s: %s
- unable to open file %s: %s
- failed to write local binary checksum file: %s
- Unrecognized checksum type: %s
- Error parsing target template: %s
AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05).
Data as JSON: /api/errors/299fffd1d29a545f.
Report an issue: GitHub.