hashicorp/packer · error
Unable to write %s: %s
Error message
Unable to write %s: %s
What it means
After appending the new build, the post-processor serializes the manifest with json.MarshalIndent and writes it to output_path via os.WriteFile. If the write fails, PostProcess returns this error while still keeping the source artifact. The build itself succeeded, but the manifest could not be persisted.
Source
Thrown at post-processor/manifest/post-processor.go:170
if err = json.Unmarshal(contents, manifestFile); err != nil {
return source, true, true, fmt.Errorf("Unable to parse content from %s: %s", p.config.OutputPath, err)
}
}
// If -force is set and we are not on same run, truncate the file. Otherwise
// we will continue to add new builds to the existing manifest file.
if p.config.PackerForce && os.Getenv("PACKER_RUN_UUID") != manifestFile.LastRunUUID {
manifestFile = &ManifestFile{}
}
// Add the current artifact to the manifest file
manifestFile.Builds = append(manifestFile.Builds, *artifact)
manifestFile.LastRunUUID = os.Getenv("PACKER_RUN_UUID")
// Write JSON to disk
if out, err := json.MarshalIndent(manifestFile, "", " "); err == nil {
if err = os.WriteFile(p.config.OutputPath, out, 0664); err != nil {
return source, true, true, fmt.Errorf("Unable to write %s: %s", p.config.OutputPath, err)
}
} else {
return source, true, true, fmt.Errorf("Unable to marshal JSON %s", err)
}
// The manifest should never delete the artifacts it is set to record, so it
// forcibly sets "keep" to true.
return source, true, true, nil
}
func createInterpolatedCustomData(config *Config, customData string) (string, error) {
interpolatedCmd, err := interpolate.Render(customData, &config.ctx)
if err != nil {
return "", fmt.Errorf("Error interpolating custom data: %s", err)
}
return interpolatedCmd, nil
}
View on GitHub (pinned to eb36e3c3e4)
Solutions
- Create the parent directory of output_path (mkdir -p) before running packer.
- Fix permissions on the existing manifest/its directory (chown/chmod) or run packer as the same user that owns it.
- Verify output_path is a file path on a writable, non-full filesystem.
- Simplify output_path to a plain writable path like `packer-manifest.json` to rule out interpolation issues.
Example fix
// before output_path = "artifacts/manifests/packer-manifest.json" // dir doesn't exist // after mkdir -p artifacts/manifests # or output_path = "packer-manifest.json"
Defensive patterns
Strategy: validation
Validate before calling
# preflight: manifest's parent dir exists, is writable, and is a file path MP="artifacts/manifests/packer-manifest.json" mkdir -p "$(dirname "$MP")" [ ! -d "$MP" ] && [ -w "$(dirname "$MP")" ] || exit 1
Prevention
- mkdir -p the parent of output_path before building.
- Verify output_path is not a directory.
- Ensure the filesystem is writable and has free space.
- Keep manifest ownership consistent with the packer user.
When it happens
Trigger: os.WriteFile(p.config.OutputPath, out, 0664) fails — output directory missing, permission denied, output_path is a directory, read-only filesystem, or disk full.
Common situations: output_path's parent directory does not exist (packer does not create nested dirs for the manifest); manifest locked/owned by another user from a prior sudo run; writing to a read-only CI volume or a path whose directory was cleaned mid-run.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Unable to open %s for reading: %s
- unable to create dir: %s
- unable to create file %s: %s
- Unable to create dir for archive %s: %s
- Unable to create archive %s: %s
AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05).
Data as JSON: /api/errors/594c04b56d5836f3.
Report an issue: GitHub.