hashicorp/packer · error

no stable Packer releases found in index at %s

Error message

no stable Packer releases found in index at %s

What it means

fetchLatestPackerVersion downloads the HashiCorp releases index (releases.hashicorp.com/packer/index.json), parses every version key with Masterminds/semver, and filters out any version carrying a prerelease suffix (alpha/beta/rc). If after that filtering no version remains, it throws this error because there is nothing to sort or select as the latest stable release. It is a guard against an empty/invalid index rather than a download failure — the HTTP fetch and JSON decode already succeeded.

Source

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

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

	sort.Sort(semver.Collection(semverList))
	latest := semverList[len(semverList)-1]
	log.Printf("[INFO] Latest stable Packer version from releases index: %s", latest.Original())
	return latest.Original(), nil
}

// downloadURLToTempFile downloads url into a new temp file and returns its path.
// On any error the temp file is removed. The caller owns the returned file on success.
func downloadURLToTempFile(ctx context.Context, client *http.Client, url, suffix string) (string, error) {
	f, err := os.CreateTemp("", "packer-dl-*"+suffix)
	if err != nil {
		return "", fmt.Errorf("failed to create temp file: %w", err)
	}
	tmpPath := f.Name()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Check that the releases index is reachable and real: curl https://releases.hashicorp.com/packer/index.json and confirm the versions map contains stable entries like "1.13.0".
  2. If using a proxy or mirror, ensure it caches the full index and does not strip stable versions or serve an empty/fixture document.
  3. If pointing the code at a custom index URL for testing, populate the fixture with at least one valid stable semver key (no prerelease suffix).
  4. Inspect the raw JSON for malformed version keys or unexpected structure and re-fetch; a corrupted cache should be purged.
  5. If only prereleases exist upstream, wait for the next stable release or pin/hardcode a known-good version instead of resolving from the index.

Example fix

// before: error surfaces only at runtime deep in the build
latest, err := fetchLatestPackerVersion(ctx, client)
// after: sanity-check the index yourself before relying on dynamic resolution
resp, _ := client.Get("https://releases.hashicorp.com/packer/index.json")
var idx releaseIndex
json.NewDecoder(resp.Body).Decode(&idx)
hasStable := false
for k := range idx.Versions {
    if v, err := semver.NewVersion(k); err == nil && v.Prerelease() == "" {
        hasStable = true
        break
    }
}
if !hasStable {
    return errors.New("release index has no stable versions; pin Packer version explicitly")
}
Defensive patterns

Strategy: validation

Validate before calling

// Check the release index yourself before invoking the fetch path
resp, err := http.Get("https://releases.hashicorp.com/packer/index.json")
if err != nil { return err }
var idx struct{ Versions map[string]json.RawMessage `json:"versions"` }
if err := json.NewDecoder(resp.Body).Decode(&idx); err != nil { return err }
resp.Body.Close()
hasStable := false
for k := range idx.Versions {
    if v, err := semver.NewVersion(k); err == nil && v.Prerelease() == "" {
        hasStable = true
        break
    }
}
if !hasStable {
    return fmt.Errorf("release index has no stable Packer versions; pin a version instead")
}

Type guard

// Ensure a parsed version is usable as the latest stable release
func isStableVersion(k string) bool {
    v, err := semver.NewVersion(k)
    return err == nil && v.Prerelease() == ""
}

Prevention

When it happens

Trigger: The index JSON decoded successfully but its 'versions' map is empty, contains only keys that semver.NewVersion cannot parse (malformed keys), or contains only prerelease versions (all keys have a -alpha/-beta/-rc suffix) so every candidate is skipped by the 'skip alpha/beta/rc' filter.

Common situations: A proxy, mirror, or corporate artifact store serves a truncated, stale, or rewritten index.json (e.g. only 1.11.0-dev entries cached); the base URL is overridden to a mock/fixture with an empty versions map; HashiCorp publishes only prerelease builds to the index; a malicious or corrupted index contains garbage version keys.

Related errors


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