{"record":{"id":"0d0e8abdf6e181b6","repo":"hashicorp/packer","slug":"download-failed-http-d-for-s","errorCode":null,"errorMessage":"download failed: HTTP %d for %s","messagePattern":"download failed: HTTP (.+?) for (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"provisioner/hcp-sbom/packer_release_fetch.go","lineNumber":158,"sourceCode":"\n\treturn tmpPath, nil\n}\n\n// downloadChecksumFile fetches the SHA256SUMS text file at url.\nfunc downloadChecksumFile(ctx context.Context, client *http.Client, url string) (string, error) {\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to build request for %s: %w\", url, err)\n\t}\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to download %s: %w\", url, err)\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn \"\", fmt.Errorf(\"download failed: HTTP %d for %s\", resp.StatusCode, url)\n\t}\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed reading response body for %s: %w\", url, err)\n\t}\n\tif len(strings.TrimSpace(string(body))) == 0 {\n\t\treturn \"\", fmt.Errorf(\"empty response body for %s\", url)\n\t}\n\n\treturn string(body), nil\n}\n\nfunc isValidSHA256Hex(s string) bool {\n\tif len(s) != 64 {\n\t\treturn false\n\t}\n\t_, err := hex.DecodeString(s)","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/provisioner/hcp-sbom/packer_release_fetch.go#L140-L176","documentation":"The HTTP request for the SHA256SUMS file succeeded at the transport level, but the server responded with a status other than 200 OK. The code deliberately rejects any non-200 status instead of reading the body, reporting the numeric status and URL so the developer can see whether the resource is missing, forbidden, or the server is erroring.","triggerScenarios":"client.Do returns a response with resp.StatusCode != http.StatusOK for <base>/packer/<v>/packer_<v>_SHA256SUMS — e.g. 404 when the resolved Packer version has no published SHA256SUMS file, 403 from a proxy/CDN block, 5xx from releases.hashicorp.com, or a captive portal returning 302/403 HTML.","commonSituations":"Newly released Packer version whose checksum files are not yet propagated on the CDN (race between index.json update and artifact publication); vendor/proxy blocking; HashiCorp releases service outage; a mirror or overridden base URL that lacks the SHA256SUMS layout.","solutions":["Check the HTTP status in the message: 404 usually means the checksum file is not yet published for that version — wait and retry, or pin an older stable Packer version","Verify releases.hashicorp.com status (curl -I <url from message>) and check HashiCorp service status for outages","If behind a corporate proxy/firewall, confirm releases.hashicorp.com is allowlisted","If using a custom/mirror base URL, confirm it mirrors the full releases layout including packer_<v>_SHA256SUMS","The download flow already retries 3 times; persistent 404s on a brand-new release usually resolve once CDN propagation completes"],"exampleFix":"// before: racing a just-released version whose SHA256SUMS is not yet on the CDN\n// after: pin a known-good Packer version until artifacts are fully published\n// (wait/retry, or use a previous stable release in your datasource config)\n// $ curl -I https://releases.hashicorp.com/packer/1.13.0/packer_1.13.0_SHA256SUMS\n// HTTP/2 404  -> retry later or pin 1.12.2","handlingStrategy":"retry","validationCode":"// probe the exact SHA256SUMS URL and inspect the status before proceeding\nshaSumsURL := fmt.Sprintf(\"%s/packer/%s/packer_%s_SHA256SUMS\", base, v, v)\nresp, err := client.Head(shaSumsURL)\nif err != nil {\n    return err\n}\n_ = resp.Body.Close()\nif resp.StatusCode == http.StatusNotFound {\n    return fmt.Errorf(\"SHA256SUMS for %s not yet published; pin an older stable version or retry later\", v)\n}","typeGuard":"// distinguish HTTP-status failures from other download errors so you can react to 404 vs 5xx\nvar statusErr interface{ HTTPStatus() int }\n// or, matching this package's message format:\nfunc parseHTTPStatus(err error) (int, bool) {\n    m := regexp.MustCompile(`HTTP (\\d{3})`).FindStringSubmatch(err.Error())\n    if m == nil {\n        return 0, false\n    }\n    code, _ := strconv.Atoi(m[1])\n    return code, true\n}","tryCatchPattern":"_, err := downloadChecksumFile(ctx, client, shaSumsURL)\nif err != nil {\n    if code, ok := parseHTTPStatus(err); ok {\n        switch {\n        case code == http.StatusNotFound:\n            return fmt.Errorf(\"checksums not published yet for this version; retry or pin older version\")\n        case code >= 500:\n            return retryErr{err} // transient, safe to retry\n        }\n        return err\n    }\n    return err\n}","preventionTips":["Avoid racing brand-new Packer releases whose CDN artifacts may lag index.json; pin a known-good version","Check HashiCorp releases service status during outages","Ensure proxies/CDNs in front of mirrors return the real status rather than HTML error pages","If mirroring, verify the mirror replicates packer_<v>_SHA256SUMS for every version","Let the built-in 3-try retry absorb transient 5xx responses"],"tags":["go","http","http-status","cdn"],"backgroundTag":"http-non-200-response","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"}