{"record":{"id":"cecf8df6a270c8cf","repo":"hashicorp/packer","slug":"failed-to-retrieve-packer-release-index-from-s","errorCode":null,"errorMessage":"failed to retrieve packer release index from %s: %w","messagePattern":"failed to retrieve packer release index from (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"provisioner/hcp-sbom/packer_release_fetch.go","lineNumber":75,"sourceCode":"\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, indexURL, nil)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to build index request: %w\", err)\n\t}\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to fetch release index: %w\", err)\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn \"\", fmt.Errorf(\"HTTP %d for %s\", resp.StatusCode, indexURL)\n\t}\n\n\terr = json.NewDecoder(resp.Body).Decode(&indexData)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to retrieve packer release index from %s: %w\", indexURL, err)\n\t}\n\n\tvar semverList []*semver.Version\n\tfor vStr := range indexData.Versions {\n\t\tv, parseErr := semver.NewVersion(vStr)\n\t\tif parseErr != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif v.Prerelease() != \"\" {\n\t\t\tcontinue // skip alpha/beta/rc\n\t\t}\n\t\tsemverList = append(semverList, v)\n\t}\n\n\tif len(semverList) == 0 {\n\t\treturn \"\", fmt.Errorf(\"no stable Packer releases found in index at %s\", indexURL)\n\t}\n","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/provisioner/hcp-sbom/packer_release_fetch.go#L57-L93","documentation":"The releases index was fetched successfully (HTTP 200) but its body could not be decoded into the expected `releaseIndex` JSON structure (`{\"versions\": {...}}`). This wraps the json.Decoder error, indicating malformed JSON, an HTML/error page served with 200, a truncated response, or an unexpectedly changed schema.","triggerScenarios":"json.NewDecoder(resp.Body).Decode(&indexData) fails after a 200 response — e.g. a proxy returned an HTML login/error page with status 200, the connection was cut mid-body, or the releases index schema changed incompatibly.","commonSituations":"Captive portal or proxy intercepting HTTPS and returning HTML with 200; TLS interception producing truncated/garbage output; content cached from a stalled connection; future schema drift on releases.hashicorp.com.","solutions":["Curl the URL from the same environment and inspect the body — HTML output means a proxy/captive portal is intercepting the request.","Bypass or correctly configure the intercepting proxy/SSL appliance so the real JSON index is served.","Retry the build — a truncated stream from a transient network fault is a common cause.","If the index schema changed, update the provisioner's releaseIndex structs to match the new JSON shape.","Verify the body is valid JSON with `curl -s <url> | jq .versions`."],"exampleFix":"// before: proxy returns HTML login page with HTTP 200\n// {\"<!DOCTYPE html>...\"}\n\n// after: bypass portal\n// curl -s https://releases.hashicorp.com/packer/index.json | head -c 80\n// {\"versions\":{\"1.13.0\":{...}}}","handlingStrategy":"validation","validationCode":"resp, err := client.Get(\"https://releases.hashicorp.com/packer/index.json\")\nif err != nil { return err }\nbody, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20))\nresp.Body.Close()\nct := resp.Header.Get(\"Content-Type\")\nif !strings.Contains(ct, \"json\") || !json.Valid(body) {\n\treturn fmt.Errorf(\"releases index not valid JSON (content-type %s); check proxy\", ct)\n}","typeGuard":"func isDecodeError(err error) bool {\n\tvar jsonErr *json.SyntaxError\n\treturn err != nil && (errors.As(err, &jsonErr) || strings.Contains(err.Error(), \"failed to retrieve packer release index\"))\n}","tryCatchPattern":"ver, err := fetchLatestPackerVersion(ctx, client)\nif err != nil {\n\tif isDecodeError(err) {\n\t\tlog.Printf(\"index body not valid JSON — likely proxy interception: %v\", err)\n\t\treturn fmt.Errorf(\"skipping latest-version lookup: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Verify Content-Type is application/json before decoding.","Check bodies with json.Valid when behind corporate proxies/captive portals.","Pin or verify TLS so interception proxies are detected.","Keep the releaseIndex struct in sync with the published index schema.","Retry on truncated-stream decode errors."],"tags":["json","network","proxy","parsing"],"backgroundTag":"json-decode-failed","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"}