hashicorp/packer · error

index.json contains no versions

Error message

index.json contains no versions

What it means

After successfully unmarshaling index.json, parseIndex requires at least one entry under `versions`. An empty or versions-less object means the remote (or cached) index advertises no plugin versions at all, so there is nothing to resolve releases from.

Solutions

  1. Verify the plugin actually has published versions on the registry/releases host.
  2. Check you are querying the correct plugin type/organization (typos route to an empty index).
  3. Re-fetch or regenerate index.json if a custom mirror served an empty file.

Example fix

// before
{"versions": {}}
// after
{"versions": {"1.1.1": {}}}
Defensive patterns

Strategy: validation

Validate before calling

var idx struct{ Versions map[string]json.RawMessage `json:"versions"` }
if json.Unmarshal(body, &idx) == nil && len(idx.Versions) == 0 {
    return errors.New("plugin has no published versions; check registry")
}

Try / catch

if _, err := g.Get("releases", opts); err != nil && strings.Contains(err.Error(), "contains no versions") {
    // verify plugin address and that releases exist upstream
}

Prevention

When it happens

Trigger: parseIndex receives valid JSON like {} or {"versions": {}}; loadIndex then returns this error to callers such as Get("releases") and versionURL.

Common situations: A newly created plugin on the registry with no published releases yet; an index.json truncated/regenerated without versions; pointing a custom plugin registry mirror at an empty bucket.

Related errors


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

Appendix: source

Thrown at packer/plugin-getter/remote/getter.go:82

// pluginIndex is the validated form of a plugin's index.json. Versions are
// keyed by their canonical core string (e.g. "1.1.4"); all other index
// content is ignored.
type pluginIndex struct {
	pluginType string
	versions   map[string]struct{}
}

// parseIndex validates raw index.json content into a pluginIndex.
func parseIndex(data []byte, pluginType string) (*pluginIndex, error) {
	var raw struct {
		Versions map[string]struct{} `json:"versions"`
	}
	if err := json.Unmarshal(data, &raw); err != nil {
		return nil, fmt.Errorf("malformed index.json: %w", err)
	}
	if len(raw.Versions) == 0 {
		return nil, fmt.Errorf("index.json contains no versions")
	}

	idx := &pluginIndex{
		pluginType: pluginType,
		versions:   map[string]struct{}{},
	}
	for k := range raw.Versions {
		ver, err := goversion.NewVersion(k)
		if err != nil {
			log.Printf("[WARN] remote-getter: ignoring unparseable version %q in index.json", k)
			continue
		}
		idx.versions[ver.String()] = struct{}{}
	}
	if len(idx.versions) == 0 {
		return nil, fmt.Errorf("index.json contains no usable versions")
	}
	return idx, nil

View on GitHub (pinned to eb36e3c3e4)