{"record":{"id":"d47b7492e5abee1f","repo":"hashicorp/nomad","slug":"nil-config-passed-for-internal-plugin-s","errorCode":null,"errorMessage":"nil config passed for internal plugin %s","messagePattern":"nil config passed for internal plugin (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/pluginutils/loader/init.go","lineNumber":44,"sourceCode":"\tvar mErr multierror.Error\n\tif config == nil {\n\t\treturn fmt.Errorf(\"nil config passed\")\n\t} else if config.Logger == nil {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"nil logger passed\"))\n\t}\n\n\t// Validate that all plugins have a binary name\n\tfor _, c := range config.Configs {\n\t\tif c.Name == \"\" {\n\t\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"plugin config passed without binary name\"))\n\t\t}\n\t}\n\n\t// Validate internal plugins\n\tfor k, config := range config.InternalPlugins {\n\t\t// Validate config\n\t\tif config == nil {\n\t\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"nil config passed for internal plugin %s\", k))\n\t\t\tcontinue\n\t\t} else if config.Factory == nil {\n\t\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"nil factory passed for internal plugin %s\", k))\n\t\t\tcontinue\n\t\t}\n\t}\n\n\treturn mErr.ErrorOrNil()\n}\n\n// init initializes the plugin loader by compiling both internal and external\n// plugins and selecting the highest versioned version of any given plugin.\nfunc (l *PluginLoader) init(cfg *PluginLoaderConfig) (map[string]*config.PluginConfig, error) {\n\t// Create a mapping of name to config\n\tconfigMap := configMap(cfg.Configs)\n\n\t// Initialize the internal plugins\n\tinternal, err := l.initInternal(cfg.InternalPlugins, configMap)","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/pluginutils/loader/init.go#L26-L62","documentation":"Each entry in config.InternalPlugins maps a plugin name to an *InternalPluginConfig. validateConfig appends this error (per named plugin) when the map value is nil, since fingerprinting an internal plugin requires its Factory and Config.","triggerScenarios":"Populating InternalPlugins with a key but a nil value, e.g. map[\"my-plugin\"] = nil, or declaring a variable of *InternalPluginConfig that was never assigned before insertion.","commonSituations":"Conditional registration code that allocates the config only under some branch; refactor where the factory/config construction was deleted but the map insertion remained; test scaffolding that stubs map keys.","solutions":["Provide a complete *InternalPluginConfig (with Factory set) for every key in InternalPlugins.","Remove map entries whose config could not be built instead of inserting nil.","Add a pre-registration check that skips/logs nil configs before calling NewPluginLoader."],"exampleFix":"// before\ninternal := map[string]*InternalPluginConfig{\"exec\": nil}\n\n// after\ninternal := map[string]*InternalPluginConfig{\n    \"exec\": {Factory: exec.NewPlugin, Config: &config.Config{}},\n}","handlingStrategy":"validation","validationCode":"for name, ipc := range cfg.InternalPlugins {\n    if ipc == nil {\n        return fmt.Errorf(\"internal plugin %q has nil config\", name)\n    }\n}\nloader, err := NewPluginLoader(cfg)","typeGuard":"func validInternalPlugins(m map[string]*InternalPluginConfig) bool {\n    for k, v := range m {\n        if v == nil || v.Factory == nil {\n            _ = k\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":"loader, err := NewPluginLoader(cfg)\nif err != nil {\n    if strings.Contains(err.Error(), \"nil config passed for internal plugin\") {\n        return fmt.Errorf(\"bad internal plugin registration: %w\", err)\n    }\n    return err\n}","preventionTips":["Only insert into InternalPlugins after the config object is fully constructed.","Skip (don't insert) optional plugins whose construction failed.","Cover internal-plugin registration in unit tests."],"tags":["go","configuration","nil-pointer","plugins"],"backgroundTag":"nil-config-passed","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"}