{"record":{"id":"54e418aa1d70fd62","repo":"hashicorp/nomad","slug":"plugin-provided-no-compatible-api-versions","errorCode":null,"errorMessage":"plugin provided no compatible API versions","messagePattern":"plugin provided no compatible API versions","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/pluginutils/loader/init.go","lineNumber":178,"sourceCode":"\t\tfingerprinted[k] = info\n\t}\n\n\tif err := mErr.ErrorOrNil(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn fingerprinted, nil\n}\n\n// selectApiVersion takes in PluginInfo and returns the highest compatable\n// version or an error if the plugins response is malformed. If there is no\n// overlap, an empty string is returned.\nfunc (l *PluginLoader) selectApiVersion(i *base.PluginInfoResponse) (string, error) {\n\tif i == nil {\n\t\treturn \"\", fmt.Errorf(\"nil plugin info given\")\n\t}\n\tif len(i.PluginApiVersions) == 0 {\n\t\treturn \"\", fmt.Errorf(\"plugin provided no compatible API versions\")\n\t}\n\n\tpluginVersions, err := convertVersions(i.PluginApiVersions)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"plugin provided invalid versions: %v\", err)\n\t}\n\n\t// Lookup the supported versions. These will be sorted highest to lowest\n\tsupportedVersions, ok := l.supportedVersions[i.Type]\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"unsupported plugin type %q\", i.Type)\n\t}\n\n\tfor _, sv := range supportedVersions {\n\t\tfor _, pv := range pluginVersions {\n\t\t\tif sv.Equal(pv) {\n\t\t\t\treturn pv.Original(), nil\n\t\t\t}","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/pluginutils/loader/init.go#L160-L196","documentation":"PluginLoader.selectApiVersion guard: the plugin's PluginInfoResponse carries an empty PluginApiVersions list, so no API version overlap with the agent is possible and the plugin is rejected as malformed.","triggerScenarios":"Plugin's PluginInfo() returns a PluginInfoResponse with PluginApiVersions set to nil or an empty slice.","commonSituations":"Custom internal plugin constructed the response without setting PluginApiVersions; plugin type template copied without filling the field.","solutions":["Populate PluginApiVersions in the plugin's PluginInfoResponse, e.g. []string{\"v1\"}","Verify against the plugin type's latest API constant (e.g. api.Version01) that the declared versions match what the plugin actually implements","Rebuild the plugin binary/agent after the fix"],"exampleFix":"// before\nreturn &base.PluginInfoResponse{Type: base.PluginTypeCSI}, nil\n// after\nreturn &base.PluginInfoResponse{Type: base.PluginTypeCSI, PluginApiVersions: []string{\"v1\"}}, nil","handlingStrategy":"validation","validationCode":"if len(info.PluginApiVersions) == 0 {\n    return errors.New(\"PluginApiVersions must list at least one version\")\n}","typeGuard":"func declaresApiVersions(info *base.PluginInfoResponse) bool {\n    return info != nil && len(info.PluginApiVersions) > 0\n}","tryCatchPattern":"if err := loader.Init(...); err != nil {\n    if strings.Contains(err.Error(), \"no compatible API versions\") {\n        // plugin forgot to declare versions; fix its PluginInfo\n    }\n}","preventionTips":["Always set PluginApiVersions alongside Type in PluginInfoResponse","Assert non-empty API versions in plugin unit tests","Copy from the official plugin template which includes the field"],"tags":["go","plugin-loader","api-version","nomad"],"backgroundTag":"missing-api-version","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}