{"record":{"id":"480208cf1d15c5f1","repo":"hashicorp/nomad","slug":"nil-plugin-info-given","errorCode":null,"errorMessage":"nil plugin info given","messagePattern":"nil plugin info given","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/pluginutils/loader/init.go","lineNumber":175,"sourceCode":"\t\tinfo.configSchema = schema\n\n\t\t// Store the fingerprinted config\n\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 {","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/pluginutils/loader/init.go#L157-L193","documentation":"PluginLoader.selectApiVersion guard: the passed *base.PluginInfoResponse is nil, meaning a plugin (internal or fingerprinted) returned no info object; the loader treats it as a malformed plugin response.","triggerScenarios":"A caller of selectApiVersion (initInternal, fingerprintPlugin, dispensePlugin) passes the result of a PluginInfo() call that was nil or was passed through without a nil check, e.g. ignoring the nil-return path of a base plugin implementation.","commonSituations":"A base plugin implementation returns (nil, nil) from PluginInfo, or an earlier fingerprint step stored a nil PluginInfoResponse and dispense later negotiates with it.","solutions":["Fix the plugin's PluginInfo() to never return a nil response with a nil error; return a populated PluginInfoResponse","Add a nil check at the call site before invoking selectApiVersion","Re-fingerprint the plugin after fixing so a valid PluginInfoResponse is cached"],"exampleFix":"// before\ninfo, err := p.PluginInfo() // returns nil, nil\n// after\nif info == nil { return nil, errors.New(\"plugin returned nil info\") }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func hasPluginInfo(p base.BasePlugin) bool {\n    if p == nil { return false }\n    i, err := p.PluginInfo()\n    return err == nil && i != nil\n}","tryCatchPattern":"if info == nil {\n    return nil, fmt.Errorf(\"nil plugin info\") // mirror the loader's guard before calling selectApiVersion\n}","preventionTips":["Never return (nil, nil) from PluginInfo; return a populated response or an error","Check fingerprint results for nil before caching them","Run nilaway/lint checks on plugin implementations"],"tags":["go","plugin-loader","nil-pointer","nomad"],"backgroundTag":"nil-plugin-info","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"}