hashicorp/packer · error

failed to open downloaded zip: %w

Error message

failed to open downloaded zip: %w

What it means

Wrapped when zip.OpenReader cannot open the downloaded release zip. The file downloaded but is not a readable zip archive — typically because it is corrupt/truncated, or because the server returned an error page (HTML/JSON) with a 200 status that got saved as the 'zip'.

Source

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

		actualSHA, err := fileSHA256(candidateZipPath)
		if err != nil {
			return err
		}

		if !strings.EqualFold(expectedSHA, actualSHA) {
			return fmt.Errorf("checksum mismatch for %s: expected %s, got %s", fileName, expectedSHA, actualSHA)
		}

		// Validate the expected binary exists inside the archive.
		binaryName := "packer"
		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
	})

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Inspect the temp file contents (e.g. `file packer-dl-*.zip` or head it) to see what was actually downloaded.
  2. Bypass or fix HTTP proxies/captive portals that may inject HTML with 200 status.
  3. Re-run the build to get a fresh download; free disk space if the disk is full.
  4. Check checksum error patterns in earlier logs to correlate corruption timing.

Example fix

// diagnostic before retrying
if b, err := os.ReadFile(candidateZipPath); err == nil && len(b) > 4 {
	log.Printf("zip magic bytes: %x", b[:4]) // expect 504b0304 ('PK\x03\x04')
}
Defensive patterns

Strategy: validation

Validate before calling

f, err := os.Open(zipPath)
if err != nil {
	return err
}
magic := make([]byte, 4)
io.ReadFull(f, magic)
f.Close()
if !bytes.Equal(magic, []byte{0x50, 0x4B, 0x03, 0x04}) {
	return fmt.Errorf("downloaded file is not a zip (magic %x); likely an error page saved with HTTP 200", magic)
}

Try / catch

if err := run(); err != nil {
	if strings.Contains(err.Error(), "failed to open downloaded zip") {
		// inspect the temp file content, fix proxy, then retry the download
	}
}

Prevention

When it happens

Trigger: zip.OpenReader(candidateZipPath) returns a non-nil error on the just-downloaded temp file — invalid zip signature, truncated archive, or non-zip content saved by downloadURLToTempFile.

Common situations: Proxy/captive portal returning a 200 HTML block page instead of the zip; interrupted transfer that still produced a 200; CDN serving garbage; disk corruption in /tmp; extremely constrained disk causing partial writes.

Related errors


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