{"record":{"id":"aaf716530a715484","repo":"hashicorp/packer","slug":"index-json-contains-no-usable-versions","errorCode":null,"errorMessage":"index.json contains no usable versions","messagePattern":"index\\.json contains no usable versions","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packer/plugin-getter/remote/getter.go","lineNumber":98,"sourceCode":"\t}\n\tif len(raw.Versions) == 0 {\n\t\treturn nil, fmt.Errorf(\"index.json contains no versions\")\n\t}\n\n\tidx := &pluginIndex{\n\t\tpluginType: pluginType,\n\t\tversions:   map[string]struct{}{},\n\t}\n\tfor k := range raw.Versions {\n\t\tver, err := goversion.NewVersion(k)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"[WARN] remote-getter: ignoring unparseable version %q in index.json\", k)\n\t\t\tcontinue\n\t\t}\n\t\tidx.versions[ver.String()] = struct{}{}\n\t}\n\tif len(idx.versions) == 0 {\n\t\treturn nil, fmt.Errorf(\"index.json contains no usable versions\")\n\t}\n\treturn idx, nil\n}\n\n// releasesStream encodes the index versions as the json list of Release that\n// Packer expects from get 'releases'.\nfunc (idx *pluginIndex) releasesStream() (io.ReadCloser, error) {\n\tout := make([]plugingetter.Release, 0, len(idx.versions))\n\tfor v := range idx.versions {\n\t\tout = append(out, plugingetter.Release{Version: \"v\" + v})\n\t}\n\tbuf := &bytes.Buffer{}\n\tif err := json.NewEncoder(buf).Encode(out); err != nil {\n\t\treturn nil, err\n\t}\n\treturn io.NopCloser(buf), nil\n}\n","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/packer/plugin-getter/remote/getter.go#L80-L116","documentation":"parseIndex filters the raw version keys through semantic-version parsing; keys that don't parse are logged as WARN and skipped. If every version key fails to parse, idx.versions ends up empty and the index — while structurally valid — is useless, so parseIndex fails with this error.","triggerScenarios":"index.json's versions map contains only keys that are not valid semver strings (e.g. \"latest\", \"v\", \"1.1\", \"master\"), so all entries are skipped and len(idx.versions) == 0.","commonSituations":"A custom/self-hosted plugin registry using non-semver tags like branch names or date strings; hand-edited index.json with typo'd versions (\"1.1.1.1\"); a registry migrated to a different tagging scheme.","solutions":["Fix the version keys in index.json to be valid semantic versions (e.g. \"1.1.1\" not \"v1.1.x\" or \"latest\").","Re-sync the custom registry/mirror against the official releases so semver tags are used.","Check the WARN log lines — they name each unparseable version key that was skipped."],"exampleFix":"// before\n{\"versions\": {\"latest\": {}, \"master\": {}}}\n// after\n{\"versions\": {\"1.1.1\": {}, \"1.1.0\": {}}}","handlingStrategy":"validation","validationCode":"for k := range rawVersions {\n    if _, err := semver.Parse(strings.TrimPrefix(k, \"v\")); err != nil {\n        return fmt.Errorf(\"version key %q is not semver\", k)\n    }\n}","typeGuard":null,"tryCatchPattern":"if _, err := g.Get(\"releases\", opts); err != nil && strings.Contains(err.Error(), \"no usable versions\") {\n    // fix non-semver tags in the custom registry index, then retry\n}","preventionTips":["Use strict semver tags (v-prefixed or plain X.Y.Z) for plugin releases.","Avoid branch names, \"latest\", or multi-dot versions as registry tags.","Watch for the WARN log lines listing skipped version keys."],"tags":["packer","plugin-getter","semver","index-validation"],"backgroundTag":"invalid-semver-tag","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"}