{"record":{"id":"b4aa7c31c1bb052c","repo":"hashicorp/nomad","slug":"nil-logger-passed","errorCode":null,"errorMessage":"nil logger passed","messagePattern":"nil logger passed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/pluginutils/loader/init.go","lineNumber":30,"sourceCode":"\t\"sort\"\n\n\tmultierror \"github.com/hashicorp/go-multierror\"\n\tplugin \"github.com/hashicorp/go-plugin\"\n\tversion \"github.com/hashicorp/go-version\"\n\t\"github.com/hashicorp/nomad/helper/pluginutils/hclspecutils\"\n\t\"github.com/hashicorp/nomad/helper/pluginutils/hclutils\"\n\t\"github.com/hashicorp/nomad/nomad/structs/config\"\n\t\"github.com/hashicorp/nomad/plugins/base\"\n\t\"github.com/zclconf/go-cty/cty/msgpack\"\n)\n\n// validateConfig returns whether or not the configuration is valid\nfunc validateConfig(config *PluginLoaderConfig) error {\n\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","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/pluginutils/loader/init.go#L12-L48","documentation":"validateConfig requires PluginLoaderConfig.Logger to be set because the loader needs a logger for plugin lifecycle events (scanning, fingerprinting, shutdown). When config is non-nil but Logger is nil, this error is appended to a multierror and returned to NewPluginLoader.","triggerScenarios":"Passing a &PluginLoaderConfig{...} struct literal that omits the Logger field, or explicitly setting Logger: nil.","commonSituations":"Struct literal construction where only some fields are filled; a logger initialized lazily after NewPluginLoader is called; test code that assumes a default logger exists.","solutions":["Set Logger on the config, e.g. hclog.New(&hclog.LoggerOptions{Level: hclog.Trace}).","Use hclog.NewNullLogger() if no log output is desired.","Share an existing application logger so plugin output goes to the same sink."],"exampleFix":"// before\ncfg := &PluginLoaderConfig{PluginDir: dir}\n\n// after\ncfg := &PluginLoaderConfig{\n    PluginDir: dir,\n    Logger:    hclog.New(&hclog.LoggerOptions{Name: \"plugins\", Level: hclog.Info}),\n}","handlingStrategy":"validation","validationCode":"if cfg == nil || cfg.Logger == nil {\n    return fmt.Errorf(\"plugin loader config requires a logger\")\n}\nloader, err := NewPluginLoader(cfg)","typeGuard":"func hasLogger(cfg *PluginLoaderConfig) bool { return cfg != nil && cfg.Logger != nil }","tryCatchPattern":"loader, err := NewPluginLoader(cfg)\nif err != nil {\n    if strings.Contains(err.Error(), \"nil logger passed\") {\n        cfg.Logger = hclog.NewNullLogger()\n        loader, err = NewPluginLoader(cfg)\n    }\n    return err\n}","preventionTips":["Centralize loader-config construction in one helper that always sets Logger.","Default to hclog.NewNullLogger() in tests instead of leaving the field unset.","Consider a NewPluginLoaderConfig() builder that assigns a default logger."],"tags":["go","configuration","logging","validation"],"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"}