hashicorp/nomad · error
plugin %s doesn't implement base plugin interface
Error message
plugin %s doesn't implement base plugin interface
What it means
After launching a plugin instance, Dispense casts instance.Plugin() to base.BasePlugin; if the cast fails the instance is killed and this error returned. The launched binary does not speak the required base plugin interface, so the loader cannot set config on it or use it.
Source
Thrown at helper/pluginutils/loader/loader.go:194
ctx, cancel := context.WithCancel(context.Background())
instance = &internalPluginInstance{
instance: pinfo.factory(ctx, logger),
apiVersion: pinfo.apiVersion,
killFn: cancel,
}
} else {
var err error
instance, err = l.dispensePlugin(pinfo.baseInfo.Type, pinfo.apiVersion, pinfo.exePath, pinfo.args, nil, logger)
if err != nil {
return nil, fmt.Errorf("failed to launch plugin: %v", err)
}
}
// Cast to the base type and set the config
b, ok := instance.Plugin().(base.BasePlugin)
if !ok {
instance.Kill() // Ensure plugin is not left running
return nil, fmt.Errorf("plugin %s doesn't implement base plugin interface", id)
}
c := &base.Config{
PluginConfig: pinfo.msgpackConfig,
AgentConfig: config,
ApiVersion: pinfo.apiVersion,
}
if err := b.SetConfig(c); err != nil {
instance.Kill() // ensure plugin is not left running
return nil, fmt.Errorf("setting config for plugin %s failed: %v", id, err)
}
return instance, nil
}
// Reattach reattaches to a previously launched external plugin.
func (l *PluginLoader) Reattach(name, pluginType string, config *plugin.ReattachConfig) (PluginInstance, error) {View on GitHub (pinned to 482b49bf1a)
Solutions
- Rebuild the plugin against the Nomad plugin SDK version matching the agent so it serves base.BasePlugin.
- Confirm the binary is the intended plugin (correct name, correct plugin type registration).
- Check the plugin's gRPC server registers the base plugin service, not only the driver/device service.
- Verify API version compatibility between plugin and agent.
Example fix
// before (plugin main.go)
plugin.Serve(&plugin.ServeConfig{PluginFunc: func() interface{} { return &MyDriver{} }})
// after (also serve/upgrade to the base plugin interface per current SDK)
plugin.Serve(&plugin.ServeConfig{
PluginFunc: func() interface{} { return &MyDriver{} }, // ensure type implements base.BasePlugin
}) Defensive patterns
Strategy: type-guard
Type guard
func asBasePlugin(inst loader.PluginInstance) (base.BasePlugin, bool) {
if inst == nil || inst.Plugin() == nil {
return nil, false
}
b, ok := inst.Plugin().(base.BasePlugin)
return b, ok
} Try / catch
inst, err := l.Dispense(name, ptype, agentCfg, logger)
if err != nil && strings.Contains(err.Error(), "doesn't implement base plugin interface") {
return fmt.Errorf("plugin binary incompatible with agent SDK; rebuild against current nomad-sdk: %w", err)
} Prevention
- Build all external plugins against the Nomad plugin SDK version the agent expects
- Ensure custom go-plugin servers implement and register base.BasePlugin
- Verify plugin type registration matches the directory/type it's served under
When it happens
Trigger: Dispense of a plugin whose dispensed PluginInstance does not implement base.BasePlugin — the binary serves a different plugin type/protocol, or a custom/incompatible go-plugin implementation returns a type not exposing the base plugin service.
Common situations: Pointing plugin_dir at a plugin built against an old Nomad plugin SDK without the base interface; mixing up binaries (a non-base plugin in the dir); hand-rolled go-plugin server that registers only a type-specific service without base.BasePlugin.
Related errors
- plugin loaded does not implement the driver interface
- unexpected executor rpc type: %T
- PluginInfo info failed for internal plugin %s: %v
- failed to parse version %q for internal plugin %s: %v
- failed to validate API versions %v for internal plugin %s: %
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/c317203a7af95169.
Report an issue: GitHub.