{"record":{"id":"45663cce975704b8","repo":"hashicorp/packer","slug":"failed-to-open-downloaded-zip-w","errorCode":null,"errorMessage":"failed to open downloaded zip: %w","messagePattern":"failed to open downloaded zip: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"provisioner/hcp-sbom/packer_release_fetch.go","lineNumber":276,"sourceCode":"\n\t\tactualSHA, err := fileSHA256(candidateZipPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !strings.EqualFold(expectedSHA, actualSHA) {\n\t\t\treturn fmt.Errorf(\"checksum mismatch for %s: expected %s, got %s\", fileName, expectedSHA, actualSHA)\n\t\t}\n\n\t\t// Validate the expected binary exists inside the archive.\n\t\tbinaryName := \"packer\"\n\t\tif goos == \"windows\" {\n\t\t\tbinaryName = \"packer.exe\"\n\t\t}\n\n\t\tzr, err := zip.OpenReader(candidateZipPath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to open downloaded zip: %w\", err)\n\t\t}\n\t\tdefer func() { _ = zr.Close() }()\n\n\t\tfoundBinary := false\n\t\tfor _, f := range zr.File {\n\t\t\tif f.Name == binaryName {\n\t\t\t\tfoundBinary = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !foundBinary {\n\t\t\treturn fmt.Errorf(\"packer binary %q not found in release zip %s\", binaryName, zipURL)\n\t\t}\n\n\t\tkeepCandidate = true\n\t\tzipPath = candidateZipPath\n\t\treturn nil\n\t})","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/provisioner/hcp-sbom/packer_release_fetch.go#L258-L294","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the temp file contents (e.g. `file packer-dl-*.zip` or head it) to see what was actually downloaded.","Bypass or fix HTTP proxies/captive portals that may inject HTML with 200 status.","Re-run the build to get a fresh download; free disk space if the disk is full.","Check checksum error patterns in earlier logs to correlate corruption timing."],"exampleFix":"// diagnostic before retrying\nif b, err := os.ReadFile(candidateZipPath); err == nil && len(b) > 4 {\n\tlog.Printf(\"zip magic bytes: %x\", b[:4]) // expect 504b0304 ('PK\\x03\\x04')\n}","handlingStrategy":"validation","validationCode":"f, err := os.Open(zipPath)\nif err != nil {\n\treturn err\n}\nmagic := make([]byte, 4)\nio.ReadFull(f, magic)\nf.Close()\nif !bytes.Equal(magic, []byte{0x50, 0x4B, 0x03, 0x04}) {\n\treturn fmt.Errorf(\"downloaded file is not a zip (magic %x); likely an error page saved with HTTP 200\", magic)\n}","typeGuard":null,"tryCatchPattern":"if err := run(); err != nil {\n\tif strings.Contains(err.Error(), \"failed to open downloaded zip\") {\n\t\t// inspect the temp file content, fix proxy, then retry the download\n\t}\n}","preventionTips":["Bypass proxies/captive portals that return 200 HTML pages","Check Content-Type is application/zip when pre-flighting the URL","Keep adequate free space in TMPDIR to avoid truncated writes","Retry corrupted downloads once before investigating infra"],"tags":["zip","archive","download","corruption"],"backgroundTag":"invalid-zip-archive","analyzedSha":"eb36e3c3e48a036f3e8cc94087636ee72e1303c9","analyzedAt":"2026-09-05T13:20:43.127Z","contentChangedAt":"2026-09-05T13:20:43.127Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}