hashicorp/packer · error

failed to retrieve packer release index from %s: %w

Error message

failed to retrieve packer release index from %s: %w

What it means

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.

Source

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

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, indexURL, nil)
	if err != nil {
		return "", fmt.Errorf("failed to build index request: %w", err)
	}

	resp, err := client.Do(req)
	if err != nil {
		return "", fmt.Errorf("failed to fetch release index: %w", err)
	}
	defer func() { _ = resp.Body.Close() }()

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("HTTP %d for %s", resp.StatusCode, indexURL)
	}

	err = json.NewDecoder(resp.Body).Decode(&indexData)
	if err != nil {
		return "", fmt.Errorf("failed to retrieve packer release index from %s: %w", indexURL, err)
	}

	var semverList []*semver.Version
	for vStr := range indexData.Versions {
		v, parseErr := semver.NewVersion(vStr)
		if parseErr != nil {
			continue
		}
		if v.Prerelease() != "" {
			continue // skip alpha/beta/rc
		}
		semverList = append(semverList, v)
	}

	if len(semverList) == 0 {
		return "", fmt.Errorf("no stable Packer releases found in index at %s", indexURL)
	}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Curl the URL from the same environment and inspect the body — HTML output means a proxy/captive portal is intercepting the request.
  2. Bypass or correctly configure the intercepting proxy/SSL appliance so the real JSON index is served.
  3. Retry the build — a truncated stream from a transient network fault is a common cause.
  4. If the index schema changed, update the provisioner's releaseIndex structs to match the new JSON shape.
  5. Verify the body is valid JSON with `curl -s <url> | jq .versions`.

Example fix

// before: proxy returns HTML login page with HTTP 200
// {"<!DOCTYPE html>..."}

// after: bypass portal
// curl -s https://releases.hashicorp.com/packer/index.json | head -c 80
// {"versions":{"1.13.0":{...}}}
Defensive patterns

Strategy: validation

Validate before calling

resp, err := client.Get("https://releases.hashicorp.com/packer/index.json")
if err != nil { return err }
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
resp.Body.Close()
ct := resp.Header.Get("Content-Type")
if !strings.Contains(ct, "json") || !json.Valid(body) {
	return fmt.Errorf("releases index not valid JSON (content-type %s); check proxy", ct)
}

Type guard

func isDecodeError(err error) bool {
	var jsonErr *json.SyntaxError
	return err != nil && (errors.As(err, &jsonErr) || strings.Contains(err.Error(), "failed to retrieve packer release index"))
}

Try / catch

ver, err := fetchLatestPackerVersion(ctx, client)
if err != nil {
	if isDecodeError(err) {
		log.Printf("index body not valid JSON — likely proxy interception: %v", err)
		return fmt.Errorf("skipping latest-version lookup: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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