hashicorp/nomad · error

nil config passed for internal plugin %s

Error message

nil config passed for internal plugin %s

What it means

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.

Source

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

	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
		}
	}

	return mErr.ErrorOrNil()
}

// init initializes the plugin loader by compiling both internal and external
// plugins and selecting the highest versioned version of any given plugin.
func (l *PluginLoader) init(cfg *PluginLoaderConfig) (map[string]*config.PluginConfig, error) {
	// Create a mapping of name to config
	configMap := configMap(cfg.Configs)

	// Initialize the internal plugins
	internal, err := l.initInternal(cfg.InternalPlugins, configMap)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Provide a complete *InternalPluginConfig (with Factory set) for every key in InternalPlugins.
  2. Remove map entries whose config could not be built instead of inserting nil.
  3. Add a pre-registration check that skips/logs nil configs before calling NewPluginLoader.

Example fix

// before
internal := map[string]*InternalPluginConfig{"exec": nil}

// after
internal := map[string]*InternalPluginConfig{
    "exec": {Factory: exec.NewPlugin, Config: &config.Config{}},
}
Defensive patterns

Strategy: validation

Validate before calling

for name, ipc := range cfg.InternalPlugins {
    if ipc == nil {
        return fmt.Errorf("internal plugin %q has nil config", name)
    }
}
loader, err := NewPluginLoader(cfg)

Type guard

func validInternalPlugins(m map[string]*InternalPluginConfig) bool {
    for k, v := range m {
        if v == nil || v.Factory == nil {
            _ = k
            return false
        }
    }
    return true
}

Try / catch

loader, err := NewPluginLoader(cfg)
if err != nil {
    if strings.Contains(err.Error(), "nil config passed for internal plugin") {
        return fmt.Errorf("bad internal plugin registration: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: 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.

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

Related errors


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