hashicorp/packer · error

unable to open file %s: %s

Error message

unable to open file %s: %s

What it means

PostProcess-time failure in the checksum post-processor: it opens each artifact file from the input artifact with os.Open to hash it; when the artifact file cannot be opened, the writer is closed and the whole post-process aborts with keep=true. The artifact path and wrapped OS error are reported.

Source

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

			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()
		}
	}

	// sets keep and forceOverride to true because we don't want to accidentally
	// delete the very artifact we're checksumming.
	return newartifact, true, true, nil
}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Verify the artifact files still exist at the reported paths at the time PostProcess runs
  2. Reorder post-processors so checksum runs directly on the builder output if a prior post-processor moves/deletes files
  3. Check file permissions on the artifact output directory and files
  4. Keep output files in the same directory tree Packer wrote them to and avoid external cleanup during the build

Example fix

// before
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())
}
// after
fr, err := os.Open(art)
if err != nil {
  fw.Close()
  return nil, false, true, fmt.Errorf("unable to open file %s: %w", art, err)
}
Defensive patterns

Strategy: validation

Validate before calling

// Go: verify every artifact file exists before post-processing
for _, f := range artifact.Files() {
    if _, err := os.Stat(f); err != nil {
        log.Fatalf("artifact file missing before checksum: %s: %v", f, err)
    }
}

Try / catch

artifact, _, _, err := pp.PostProcess(ctx, ui, art)
if err != nil {
    if strings.Contains(err.Error(), "unable to open file") {
        // artifact files vanished: fix post-processor order / stale paths
    }
    return err
}

Prevention

When it happens

Trigger: os.Open(art) fails for a file listed in the artifact's Files() — the builder's output was deleted/moved between build and post-process, the artifact reports a stale path (common with chained post-processors like compress/artifice changing output locations), or permissions changed.

Common situations: Chaining checksum after another post-processor that consumed/renamed the files; running on shared output where the file was cleaned up; the builder emitting file paths that were relative to a different working directory.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


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