hashicorp/nomad · error

nil logger passed

Error message

nil logger passed

What it means

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.

Source

Thrown at helper/pluginutils/loader/init.go:30

	"sort"

	multierror "github.com/hashicorp/go-multierror"
	plugin "github.com/hashicorp/go-plugin"
	version "github.com/hashicorp/go-version"
	"github.com/hashicorp/nomad/helper/pluginutils/hclspecutils"
	"github.com/hashicorp/nomad/helper/pluginutils/hclutils"
	"github.com/hashicorp/nomad/nomad/structs/config"
	"github.com/hashicorp/nomad/plugins/base"
	"github.com/zclconf/go-cty/cty/msgpack"
)

// validateConfig returns whether or not the configuration is valid
func validateConfig(config *PluginLoaderConfig) error {
	var mErr multierror.Error
	if config == nil {
		return fmt.Errorf("nil config passed")
	} else if config.Logger == nil {
		_ = multierror.Append(&mErr, fmt.Errorf("nil logger passed"))
	}

	// Validate that all plugins have a binary name
	for _, c := range config.Configs {
		if c.Name == "" {
			_ = multierror.Append(&mErr, fmt.Errorf("plugin config passed without binary name"))
		}
	}

	// Validate internal plugins
	for k, config := range config.InternalPlugins {
		// Validate config
		if config == nil {
			_ = multierror.Append(&mErr, fmt.Errorf("nil config passed for internal plugin %s", k))
			continue
		} else if config.Factory == nil {
			_ = multierror.Append(&mErr, fmt.Errorf("nil factory passed for internal plugin %s", k))
			continue

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set Logger on the config, e.g. hclog.New(&hclog.LoggerOptions{Level: hclog.Trace}).
  2. Use hclog.NewNullLogger() if no log output is desired.
  3. Share an existing application logger so plugin output goes to the same sink.

Example fix

// before
cfg := &PluginLoaderConfig{PluginDir: dir}

// after
cfg := &PluginLoaderConfig{
    PluginDir: dir,
    Logger:    hclog.New(&hclog.LoggerOptions{Name: "plugins", Level: hclog.Info}),
}
Defensive patterns

Strategy: validation

Validate before calling

if cfg == nil || cfg.Logger == nil {
    return fmt.Errorf("plugin loader config requires a logger")
}
loader, err := NewPluginLoader(cfg)

Type guard

func hasLogger(cfg *PluginLoaderConfig) bool { return cfg != nil && cfg.Logger != nil }

Try / catch

loader, err := NewPluginLoader(cfg)
if err != nil {
    if strings.Contains(err.Error(), "nil logger passed") {
        cfg.Logger = hclog.NewNullLogger()
        loader, err = NewPluginLoader(cfg)
    }
    return err
}

Prevention

When it happens

Trigger: Passing a &PluginLoaderConfig{...} struct literal that omits the Logger field, or explicitly setting Logger: nil.

Common situations: 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.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/b4aa7c31c1bb052c. Report an issue: GitHub.