m1k1o/neko · error
failed to add plugin: %w
Error message
failed to add plugin: %w
What it means
Returned by Manager.load when manager.plugins.addPlugin(p) fails; load wraps the underlying error (duplicate plugin — error 60, or cyclical dependency — error 61) with this message. It is a wrapper: the real cause is always in the wrapped %w chain.
Source
Thrown at server/internal/plugins/manager.go:96
func (manager *ManagerCtx) load(path string) error {
pl, err := plugin.Open(path)
if err != nil {
return err
}
sym, err := pl.Lookup("Plugin")
if err != nil {
return err
}
p, ok := sym.(types.Plugin)
if !ok {
return fmt.Errorf("not a valid plugin")
}
if err = manager.plugins.addPlugin(p); err != nil {
return fmt.Errorf("failed to add plugin: %w", err)
}
return nil
}
func (manager *ManagerCtx) InitConfigs(cmd *cobra.Command) {
_ = manager.plugins.forEach(func(d *dependency) error {
if err := d.plugin.Config().Init(cmd); err != nil {
log.Err(err).Str("plugin", d.plugin.Name()).Msg("unable to initialize configuration")
}
return nil
})
}
func (manager *ManagerCtx) SetConfigs() {
_ = manager.plugins.forEach(func(d *dependency) error {
d.plugin.Config().Set()
return nilView on GitHub (pinned to b0f01cedea)
Solutions
- Inspect the wrapped error chain (errors.Unwrap / %v of the error) to find whether it is 'already added' or 'cyclical dependency'
- For duplicates: assign a unique Name() per plugin or remove the earlier registration before loading
- For cycles: restructure plugin dependencies so they form a DAG (see error 61)
- If reloading, delete the old entry from d.deps before calling load again
Example fix
// before
err := manager.load(so)
// plugin 'x' loaded twice -> failed to add plugin: plugin 'x' already added
// after
if _, ok := manager.plugins.findPlugin(p.Name()); ok {
return nil // already loaded, skip
}
err := manager.load(so) Defensive patterns
Strategy: try-catch
Validate before calling
if _, ok := manager.plugins.findPlugin(name); ok {
return fmt.Errorf("skip load: %s already registered", name)
}
// and pre-check dependency graph for cycles before load
if createsCycle(manager.plugins.deps, p) {
return fmt.Errorf("refusing to load %s: dependency cycle", p.Name())
} Try / catch
if err := manager.load(soPath); err != nil {
var root error = err
for errors.Unwrap(root) != nil { root = errors.Unwrap(root) }
switch {
case strings.Contains(root.Error(), "already added"):
log.Warn().Msg("duplicate plugin, skipping")
case strings.Contains(root.Error(), "cyclical dependency"):
log.Error().Err(root).Msg("fix plugin dependency graph")
default:
return err
}
} Prevention
- Always inspect the wrapped error chain — this error is only a wrapper
- Deduplicate plugin artifacts by Name() before the load phase
- Keep the dependency graph acyclic and verified by tests
When it happens
Trigger: load() calls addPlugin and the dependency registry rejects the plugin: either a plugin with the same Name() already exists, or registering it would create a dependency cycle.
Common situations: Loading two plugin files that both report the same Name(); re-running the plugin load path without cleanup; mutually-dependent plugin configurations.
Related errors
- plugin '%s' already added
- cyclical dependency detected: '%s' <-> '%s'
- unable to unmarshal %s plugin settings from global settings:
- unable to unmarshal %s plugin settings from profile: %w
- not a valid plugin
AI-assisted analysis of m1k1o/neko@b0f01cedea (2026-09-01).
Data as JSON: /api/errors/c1312fe7eb6d103c.
Report an issue: GitHub.