{"record":{"id":"7fce67f1a5a6bb86","repo":"hashicorp/packer","slug":"empty-response-body-for-s","errorCode":null,"errorMessage":"empty response body for %s","messagePattern":"empty response body for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"provisioner/hcp-sbom/packer_release_fetch.go","lineNumber":166,"sourceCode":"\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)\n\treturn err == nil\n}\n\nfunc expectedZipSHA256FromSums(sumsContent, fileName string) (string, error) {\n\tfor _, line := range strings.Split(sumsContent, \"\\n\") {\n\t\tfields := strings.Fields(strings.TrimSpace(line))\n\t\tif len(fields) < 2 {\n\t\t\tcontinue","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/provisioner/hcp-sbom/packer_release_fetch.go#L148-L184","documentation":"downloadChecksumFile in provisioner/hcp-sbom/packer_release_fetch.go downloads a SHA256SUMS text file from releases.hashicorp.com and requires non-whitespace-only content. When the HTTP response succeeds (status 200) but the body contains only whitespace or nothing, the function rejects it with this error rather than returning an empty checksum list. This guards the downstream parser (expectedZipSHA256FromSums) from silently returning 'checksum not found' for a bogus empty file.","triggerScenarios":"downloadChecksumFile(ctx, client, url) receives an HTTP 200 response whose body, after strings.TrimSpace, has length 0 — e.g. the SHA256SUMS URL exists but serves an empty file, a proxy/CDN returns a 200 with a zero-length body, or a captive portal/interception proxy strips the body.","commonSituations":"Corporate proxies or SSL-inspecting firewalls returning empty 200 responses; a misconfigured or deprecated release mirror that still answers 200; transient CDN issues at releases.hashicorp.com; pointing a custom release base URL at a stub server that returns empty bodies.","solutions":["Retry the download — downloadPackerRelease wraps calls in a retry.Config with 3 tries and 5s delay, so transient empty responses are often resolved on retry; the error will surface only after retries are exhausted.","Check network path (proxy/VPN/firewall) for body-stripping behavior; bypass the proxy or add releases.hashicorp.com to an allowlist.","Verify the SHA256SUMS URL manually (curl -v <url>) to confirm the server actually serves checksum content; if the URL is wrong, fix the release base URL / version string used to build it.","If self-hosting a mirror, ensure the SHA256SUMS file is populated and served with correct content."],"exampleFix":"// before: failing against an empty body from a stub server\nsumsContent, err := downloadChecksumFile(ctx, client, shaSumsURL)\n\n// after: pre-check the endpoint and add explicit diagnostic logging\nresp, err := http.Get(shaSumsURL)\nif err == nil {\n    log.Printf(\"SHA256SUMS endpoint status=%d content-length=%d\", resp.StatusCode, resp.ContentLength)\n}\nsumsContent, err := downloadChecksumFile(ctx, client, shaSumsURL)","handlingStrategy":"retry","validationCode":"resp, err := http.Head(shaSumsURL)\nif err != nil {\n    return fmt.Errorf(\"checksum endpoint unreachable: %w\", err)\n}\nif resp.ContentLength == 0 {\n    return fmt.Errorf(\"SHA256SUMS endpoint reports zero-length body: %s\", shaSumsURL)\n}","typeGuard":"func hasNonEmptyBody(body []byte) bool {\n    return len(strings.TrimSpace(string(body))) > 0\n}","tryCatchPattern":"sumsContent, err := downloadChecksumFile(ctx, client, shaSumsURL)\nif err != nil {\n    if strings.Contains(err.Error(), \"empty response body\") {\n        // transient/proxy issue: back off and retry once more\n        time.Sleep(5 * time.Second)\n        sumsContent, err = downloadChecksumFile(ctx, client, shaSumsURL)\n    }\n    if err != nil {\n        return fmt.Errorf(\"cannot fetch SHA256SUMS: %w\", err)\n    }\n}","preventionTips":["Rely on downloadPackerRelease's built-in retry (3 tries, 5s delay) instead of disabling retries for flaky networks.","Audit proxy/SSL-inspection appliances for body-stripping of 200 responses.","Monitor releases.hashicorp.com availability from your build network before large batch jobs.","If mirroring, verify mirror serves full SHA256SUMS content with correct Content-Length."],"tags":["network","http","checksum","go"],"backgroundTag":"empty-http-response-body","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"}