{"record":{"id":"c1312fe7eb6d103c","repo":"m1k1o/neko","slug":"failed-to-add-plugin-w","errorCode":null,"errorMessage":"failed to add plugin: %w","messagePattern":"failed to add plugin: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/plugins/manager.go","lineNumber":96,"sourceCode":"\nfunc (manager *ManagerCtx) load(path string) error {\n\tpl, err := plugin.Open(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tsym, err := pl.Lookup(\"Plugin\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tp, ok := sym.(types.Plugin)\n\tif !ok {\n\t\treturn fmt.Errorf(\"not a valid plugin\")\n\t}\n\n\tif err = manager.plugins.addPlugin(p); err != nil {\n\t\treturn fmt.Errorf(\"failed to add plugin: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (manager *ManagerCtx) InitConfigs(cmd *cobra.Command) {\n\t_ = manager.plugins.forEach(func(d *dependency) error {\n\t\tif err := d.plugin.Config().Init(cmd); err != nil {\n\t\t\tlog.Err(err).Str(\"plugin\", d.plugin.Name()).Msg(\"unable to initialize configuration\")\n\t\t}\n\t\treturn nil\n\t})\n}\n\nfunc (manager *ManagerCtx) SetConfigs() {\n\t_ = manager.plugins.forEach(func(d *dependency) error {\n\t\td.plugin.Config().Set()\n\t\treturn nil","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/m1k1o/neko/blob/b0f01cedea68893e85a3fd852c0521238c285695/server/internal/plugins/manager.go#L78-L114","documentation":"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.","triggerScenarios":"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.","commonSituations":"Loading two plugin files that both report the same Name(); re-running the plugin load path without cleanup; mutually-dependent plugin configurations.","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"],"exampleFix":"// before\nerr := manager.load(so)\n// plugin 'x' loaded twice -> failed to add plugin: plugin 'x' already added\n\n// after\nif _, ok := manager.plugins.findPlugin(p.Name()); ok {\n    return nil // already loaded, skip\n}\nerr := manager.load(so)","handlingStrategy":"try-catch","validationCode":"if _, ok := manager.plugins.findPlugin(name); ok {\n    return fmt.Errorf(\"skip load: %s already registered\", name)\n}\n// and pre-check dependency graph for cycles before load\nif createsCycle(manager.plugins.deps, p) {\n    return fmt.Errorf(\"refusing to load %s: dependency cycle\", p.Name())\n}","typeGuard":null,"tryCatchPattern":"if err := manager.load(soPath); err != nil {\n    var root error = err\n    for errors.Unwrap(root) != nil { root = errors.Unwrap(root) }\n    switch {\n    case strings.Contains(root.Error(), \"already added\"):\n        log.Warn().Msg(\"duplicate plugin, skipping\")\n    case strings.Contains(root.Error(), \"cyclical dependency\"):\n        log.Error().Err(root).Msg(\"fix plugin dependency graph\")\n    default:\n        return err\n    }\n}","preventionTips":["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"],"tags":["go","plugins","wrapped-error","registration"],"backgroundTag":"duplicate-plugin-registration","analyzedSha":"b0f01cedea68893e85a3fd852c0521238c285695","analyzedAt":"2026-09-01T10:35:56.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}