hashicorp/packer · error

failed to open %s for hashing: %w

Error message

failed to open %s for hashing: %w

What it means

fileSHA256 computes the SHA-256 of a downloaded artifact by opening it with os.Open. If the file cannot be opened (does not exist, permission denied, path is a directory, etc.), it wraps the OS error with this message including the path. It indicates the local zip to be verified is unreadable, not that its content is wrong.

Source

Thrown at provisioner/hcp-sbom/packer_release_fetch.go:201

		if len(fields) < 2 {
			continue
		}
		candidateFileName := strings.TrimPrefix(fields[len(fields)-1], "*")
		if candidateFileName == fileName {
			hash := strings.ToLower(fields[0])
			if !isValidSHA256Hex(hash) {
				return "", fmt.Errorf("invalid SHA256 checksum format for %s in SHA256SUMS", fileName)
			}
			return hash, nil
		}
	}
	return "", fmt.Errorf("checksum for %s not found in SHA256SUMS", fileName)
}

func fileSHA256(path string) (string, error) {
	f, err := os.Open(path)
	if err != nil {
		return "", fmt.Errorf("failed to open %s for hashing: %w", path, err)
	}
	defer func() { _ = f.Close() }()

	h := sha256.New()
	if _, err := io.Copy(h, f); err != nil {
		return "", fmt.Errorf("failed hashing %s: %w", path, err)
	}

	return hex.EncodeToString(h.Sum(nil)), nil
}

// downloadPackerRelease fetches the latest stable Packer version from the
// HashiCorp releases index (releases.hashicorp.com/packer/index.json), then
// downloads and checksum-verifies the zip for the given GOOS/GOARCH.
// All HTTP operations are retried up to three times.
func downloadPackerRelease(ctx context.Context, goos, goarch string) (string, error) {
	base := getReleaseBaseURL()
	client := &http.Client{Timeout: 5 * time.Minute}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Check the wrapped OS error in the message (e.g. 'no such file or directory' vs 'permission denied') to identify the root cause.
  2. Verify TMPDIR points to a writable directory with free space (df -h /tmp); set TMPDIR to a writable location if needed.
  3. Check whether antivirus/EDR removed the downloaded file and add an exclusion for the temp download path.
  4. Confirm nothing deletes the temp file before hashing — downloadURLToTempFile removes it on error, and only the caller's keepCandidate flag preserves it.

Example fix

// before: inheriting an unwritable TMPDIR in a container
// os.Open /tmp/packer-dl-*123.zip: permission denied

// after: ensure a writable temp directory before downloading
if err := os.MkdirAll("/work/tmp", 0o755); err != nil {
    return err
}
os.Setenv("TMPDIR", "/work/tmp")
zipPath, err := downloadPackerRelease(ctx, goos, goarch)
Defensive patterns

Strategy: validation

Validate before calling

func assertReadableFile(path string) error {
    info, err := os.Stat(path)
    if err != nil {
        return fmt.Errorf("artifact missing: %w", err)
    }
    if info.IsDir() {
        return fmt.Errorf("%s is a directory, expected file", path)
    }
    f, err := os.Open(path)
    if err != nil {
        return fmt.Errorf("artifact unreadable: %w", err)
    }
    return f.Close()
}

Type guard

func isFileReadable(path string) bool {
    f, err := os.Open(path)
    if err != nil {
        return false
    }
    _ = f.Close()
    return true
}

Try / catch

actualSHA, err := fileSHA256(candidateZipPath)
if err != nil {
    var pathErr *fs.PathError
    if errors.As(err, &pathErr) {
        return fmt.Errorf("downloaded artifact %s unavailable (%v); TMPDIR=%s, free disk and AV exclusions should be checked",
            candidateZipPath, pathErr.Err, os.TempDir())
    }
    return err
}

Prevention

When it happens

Trigger: fileSHA256(path) called on the temp file produced by downloadURLToTempFile; os.Open fails with *fs.PathError — e.g. the temp file was deleted between download and hashing (cleanup defer raced), /tmp is not readable, disk full causing unlink, or a caller passes an empty/invalid path.

Common situations: Read-only or full /tmp (TMPDIR misconfigured); security software (EDR/antivirus) quarantining the downloaded binary; running with restricted permissions or a sandbox that blocks temp-file access; another process cleaning /tmp concurrently.

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/f180a0f9222e0672. Report an issue: GitHub.