hashicorp/packer · error

HTTP %d for %s

Error message

HTTP %d for %s

What it means

The Packer releases index responded with a non-200 HTTP status code. fetchLatestPackerVersion requires 200 OK before decoding the JSON index and returns the status code plus the requested URL verbatim so the caller can see which endpoint misbehaved. This indicates a server-side or routing problem rather than a local network failure.

Source

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

// fetchLatestPackerVersion queries the HashiCorp releases index, sorts all
// stable (non-prerelease) versions with semver, and returns the highest one.
func fetchLatestPackerVersion(ctx context.Context, client *http.Client) (string, error) {
	indexURL := getReleaseBaseURL() + "/packer/index.json"
	var indexData releaseIndex

	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)
	}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Check the reported status code: 403/429 suggests proxy/WAF/rate limiting; 5xx suggests a server-side outage.
  2. Retry after a delay if 429/5xx — the index is static content and transient errors are common under rate limiting.
  3. Curl the URL manually from the affected environment to reproduce and inspect response headers/body.
  4. Bypass or fix any corporate proxy/SSL-inspection appliance that is rewriting the response.
  5. Check status.hashicorp.com for a releases endpoint incident.

Example fix

// before: proxy returns 403 for releases.hashicorp.com
// curl -I https://releases.hashicorp.com/packer/index.json -> HTTP/1.1 403

// after: allowlist the host in the proxy policy
// curl -I -> HTTP/2 200
Defensive patterns

Strategy: retry

Validate before calling

resp, err := client.Get("https://releases.hashicorp.com/packer/index.json")
if err == nil {
	ok := resp.StatusCode == http.StatusOK
	resp.Body.Close()
	if !ok {
		return errors.New("releases endpoint currently returning non-200; retry later")
	}
}

Type guard

func isBadStatus(err error) (bool, int) {
	re := regexp.MustCompile(`HTTP (\d+) for`)
	if m := re.FindStringSubmatch(err.Error()); m != nil {
		n, _ := strconv.Atoi(m[1])
		return n != http.StatusOK, n
	}
	return false, 0
}

Try / catch

ver, err := fetchLatestPackerVersion(ctx, client)
if err != nil {
	if bad, code := isBadStatus(err); bad && (code == 429 || code >= 500) {
		// back off and retry once
		time.Sleep(time.Minute)
		ver, err = fetchLatestPackerVersion(ctx, client)
	}
	if err != nil {
		return err
	}
}

Prevention

When it happens

Trigger: GET https://releases.hashicorp.com/packer/index.json returned e.g. 403 (blocked by CDN/WAF, geo or rate limiting), 404 (endpoint moved), 5xx (server error), or an unexpected status like 301/403 from a misbehaving proxy.

Common situations: Corporate proxy or security appliance rewriting/blocking the request; rate limiting from shared CI egress IPs; HashiCorp releases outage; a redirect-to-error-page proxy returning 302/502.

Related errors


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