hashicorp/nomad · error
nil factory passed for internal plugin %s
Error message
nil factory passed for internal plugin %s
What it means
InternalPluginConfig.Factory is the function that instantiates the internal plugin; without it the loader cannot create the plugin during initInternal. validateConfig appends this error per named internal plugin whose config exists but has a nil Factory.
Source
Thrown at helper/pluginutils/loader/init.go:47
} 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)
if err != nil {
return nil, fmt.Errorf("failed to fingerprint internal plugins: %v", err)
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Assign the plugin constructor to Factory, e.g. Factory: func(ctx context.Context, l hclog.Logger) interface{} { return myplugin.New(ctx, l) }.
- Verify the factory has the expected signature used by plugin.Factory.
- Run validateConfig-style checks in unit tests for all registered internal plugins.
Example fix
// before
cfg := &InternalPluginConfig{Config: myCfg}
// after
cfg := &InternalPluginConfig{
Factory: func(ctx context.Context, logger hclog.Logger) interface{} {
return myplugin.New(ctx, logger)
},
Config: myCfg,
} Defensive patterns
Strategy: validation
Validate before calling
for name, ipc := range cfg.InternalPlugins {
if ipc != nil && ipc.Factory == nil {
return fmt.Errorf("internal plugin %q missing factory", name)
}
}
loader, err := NewPluginLoader(cfg) Type guard
func hasFactory(ipc *InternalPluginConfig) bool { return ipc != nil && ipc.Factory != nil } Try / catch
loader, err := NewPluginLoader(cfg)
if err != nil {
if strings.Contains(err.Error(), "nil factory passed") {
return fmt.Errorf("internal plugin factory not wired: %w", err)
}
return err
} Prevention
- Create internal plugin configs via a helper that takes the factory as a mandatory argument.
- Use a registry function (e.g. registerInternalPlugin(name, factory, cfg)) so Factory can never be omitted.
- Add compile-time references to each factory so unused/renamed constructors surface quickly.
When it happens
Trigger: Setting an InternalPluginConfig with only Config populated and leaving Factory nil; type mismatch where the factory variable was declared but never assigned; accidentally passing a struct value copy where the Factory field was dropped.
Common situations: Registering a new internal plugin and forgetting to wire its factory constructor; refactors that renamed the constructor function leaving the field unset; tests that only exercise config parsing.
Related errors
- plugin config passed without binary name
- nil config passed for internal plugin %s
- parsing plugin configurations failed: %v
- ErrPluginNotExecutable
- dynamic workload users disabled
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/3d15a0cd27f61952.
Report an issue: GitHub.