hashicorp/packer · error

packer binary %q not found in release zip %s

Error message

packer binary %q not found in release zip %s

What it means

Raised when the downloaded release zip opens fine but contains no entry exactly named 'packer' (or 'packer.exe' on Windows). The provisioner requires the bare binary at the zip root before accepting the artifact; anything else means the archive layout is not what upstream publishes.

Source

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

		if goos == "windows" {
			binaryName = "packer.exe"
		}

		zr, err := zip.OpenReader(candidateZipPath)
		if err != nil {
			return fmt.Errorf("failed to open downloaded zip: %w", err)
		}
		defer func() { _ = zr.Close() }()

		foundBinary := false
		for _, f := range zr.File {
			if f.Name == binaryName {
				foundBinary = true
				break
			}
		}
		if !foundBinary {
			return fmt.Errorf("packer binary %q not found in release zip %s", binaryName, zipURL)
		}

		keepCandidate = true
		zipPath = candidateZipPath
		return nil
	})
	if err != nil {
		return "", fmt.Errorf("failed to download and verify Packer release zip: %w", err)
	}

	log.Printf("[INFO] Downloaded and verified Packer release zip: %s", zipPath)
	return zipPath, nil
}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. List the zip contents (unzip -l) and compare against the official release layout.
  2. Confirm the binary name expectation ('packer' vs 'packer.exe') matches the actual archive for that GOOS.
  3. If upstream changed packaging, update the provisioner to a version aware of the new layout.
  4. Re-download from releases.hashicorp.com directly, avoiding mirrors/caches.

Example fix

// resilient lookup if layout changes upstream
foundBinary := false
for _, f := range zr.File {
	if f.Name == binaryName || strings.HasSuffix(f.Name, "/"+binaryName) {
		foundBinary = true
		break
	}
}
Defensive patterns

Strategy: type-guard

Validate before calling

zr, err := zip.OpenReader(zipPath)
if err != nil {
	return err
}
defer zr.Close()
binaryName := "packer"
if goos == "windows" {
	binaryName = "packer.exe"
}
found := false
for _, f := range zr.File {
	if f.Name == binaryName || strings.HasSuffix(f.Name, "/"+binaryName) {
		found = true
		break
	}
}
if !found {
	return fmt.Errorf("unexpected archive layout: %s missing from %s", binaryName, zipPath)
}

Type guard

func hasRootBinary(zr *zip.ReadCloser, name string) bool {
	for _, f := range zr.File {
		if f.Name == name {
			return true
		}
	}
	return false
}

Prevention

When it happens

Trigger: After iterating zr.File, no entry has f.Name == binaryName ('packer' or 'packer.exe'), so foundBinary stays false and the error is returned with the zipURL.

Common situations: Upstream changed the archive layout (binary nested under a subdirectory or renamed); a mirror/cache served a repackaged zip; wrong GOOS value causing expectations to diverge; a corrupted-but-valid zip containing junk.

Related errors


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