{"record":{"id":"ebc30bb29b6f8577","repo":"hashicorp/nomad","slug":"internal-plugin-s-doesn-t-meet-base-plugin-interf","errorCode":null,"errorMessage":"internal plugin %s doesn't meet base plugin interface","messagePattern":"internal plugin (.+?) doesn't meet base plugin interface","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/pluginutils/loader/init.go","lineNumber":109,"sourceCode":"\t\t}\n\t}\n\n\treturn configMap, nil\n}\n\n// initInternal initializes internal plugins.\nfunc (l *PluginLoader) initInternal(plugins map[PluginID]*InternalPluginConfig, configs map[string]*config.PluginConfig) (map[PluginID]*pluginInfo, error) {\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tvar mErr multierror.Error\n\tfingerprinted := make(map[PluginID]*pluginInfo, len(plugins))\n\tfor k, config := range plugins {\n\t\t// Create an instance\n\t\traw := config.Factory(ctx, l.logger)\n\t\tbase, ok := raw.(base.BasePlugin)\n\t\tif !ok {\n\t\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"internal plugin %s doesn't meet base plugin interface\", k))\n\t\t\tcontinue\n\t\t}\n\n\t\tinfo := &pluginInfo{\n\t\t\tfactory: config.Factory,\n\t\t\tconfig:  config.Config,\n\t\t}\n\n\t\t// Try to retrieve a user specified config\n\t\tif userConfig, ok := configs[k.Name]; ok && userConfig.Config != nil {\n\t\t\tinfo.config = userConfig.Config\n\t\t}\n\n\t\t// Fingerprint base info\n\t\ti, err := base.PluginInfo()\n\t\tif err != nil {\n\t\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"PluginInfo info failed for internal plugin %s: %v\", k, err))\n\t\t\tcontinue","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/pluginutils/loader/init.go#L91-L127","documentation":"initInternal calls each internal plugin's Factory and then asserts the returned raw value implements base.BasePlugin (the interface with the gRPC Handshake/serve plumbing the loader requires). If the type assertion fails, this error is appended per plugin name and the plugin is skipped from registration.","triggerScenarios":"A Factory registered in InternalPlugins returns an object that implements only part of the required interface (e.g. a device or driver plugin interface but not base.BasePlugin), or returns nil / the wrong concrete type.","commonSituations":"Writing a custom internal plugin and returning a struct missing one of the BasePlugin methods (PluginInfo, PluginType, SetConfig, etc.); embedding errors where a required method was not promoted; returning a wrapper type that hides the interface implementation.","solutions":["Make the Factory return a type that implements the full base.BasePlugin interface (add missing methods or embed base.BasePlugin).","Use a compile-time assertion like `var _ base.BasePlugin = (*MyPlugin)(nil)` to catch this before runtime.","Check that the factory is not returning nil on the tested code path."],"exampleFix":"// before\nfunc (p *MyPlugin) PluginInfo() base.PluginInfoResponse { ... }\n// missing other BasePlugin methods\n\n// after\nvar _ base.BasePlugin = (*MyPlugin)(nil)\n\nfunc (p *MyPlugin) PluginInfo() base.PluginInfoResponse { ... }\nfunc (p *MyPlugin) PluginType() base.PluginType { ... }\nfunc (p *MyPlugin) SetConfig(c []byte) error { ... }\n// ...all remaining BasePlugin methods","handlingStrategy":"type-guard","validationCode":"probe := factory(context.Background(), logger)\nif _, ok := probe.(base.BasePlugin); !ok {\n    return fmt.Errorf(\"factory does not return a base.BasePlugin\")\n}","typeGuard":"func asBasePlugin(raw interface{}) (base.BasePlugin, bool) {\n    bp, ok := raw.(base.BasePlugin)\n    return bp, ok\n}","tryCatchPattern":"loader, err := NewPluginLoader(cfg)\nif err != nil {\n    if strings.Contains(err.Error(), \"doesn't meet base plugin interface\") {\n        return fmt.Errorf(\"internal plugin misimplemented; fix factory return type: %w\", err)\n    }\n    return err\n}","preventionTips":["Add a compile-time check `var _ base.BasePlugin = (*MyPlugin)(nil)` next to every internal plugin.","Never return nil or wrapper types from plugin factories.","Cover factory output with an interface-satisfaction unit test."],"tags":["go","plugins","type-assertion","interface"],"backgroundTag":"interface-not-implemented","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"}