{"record":{"id":"195f1932d177f7c8","repo":"m1k1o/neko","slug":"plugin-s-s-dependency-w","errorCode":null,"errorMessage":"plugin's '%s' dependency: %w","messagePattern":"plugin's '(.+?)' dependency: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/plugins/dependency.go","lineNumber":46,"sourceCode":"\t\tplug, ok := dep.findPlugin(name)\n\t\tif ok {\n\t\t\treturn plug, true\n\t\t}\n\t}\n\n\treturn nil, false\n}\n\nfunc (a *dependency) startPlugin(pm types.PluginManagers) error {\n\tif a.invoked {\n\t\treturn nil\n\t}\n\n\ta.invoked = true\n\n\tfor _, do := range a.dependsOn {\n\t\tif err := do.startPlugin(pm); err != nil {\n\t\t\treturn fmt.Errorf(\"plugin's '%s' dependency: %w\", a.plugin.Name(), err)\n\t\t}\n\t}\n\n\terr := a.plugin.Start(pm)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"plugin '%s' failed to start: %w\", a.plugin.Name(), err)\n\t}\n\n\ta.logger.Info().Str(\"plugin\", a.plugin.Name()).Msg(\"plugin started\")\n\treturn nil\n}\n\ntype dependiencies struct {\n\tdeps   map[string]*dependency\n\tlogger zerolog.Logger\n}\n\nfunc (d *dependiencies) addPlugin(plugin types.Plugin) error {","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/m1k1o/neko/blob/b0f01cedea68893e85a3fd852c0521238c285695/server/internal/plugins/dependency.go#L28-L64","documentation":"The plugin manager starts plugins as a dependency graph: startPlugin first recursively starts everything in a.dependsOn before starting the plugin itself. If a dependency's own startPlugin fails, the error is wrapped as fmt.Errorf(\"plugin's '%s' dependency: %w\", a.plugin.Name(), err), attributing the failure to the dependent plugin's dependency chain while preserving the underlying cause via %w.","triggerScenarios":"Calling Start on a plugin whose dependsOn list contains a plugin that fails to start — either its own Start() returned an error or a deeper transitive dependency failed, so each level of the chain wraps the error with its own \"plugin's 'X' dependency\" prefix.","commonSituations":"A plugin enabled in config requires another plugin that is disabled or missing; the dependency plugin panics or returns an error during Start (bad config, failed port bind, missing external service); circular or stale dependency lists after a plugin rename or upgrade.","solutions":["Read the wrapped chain to the innermost error — it names the actual plugin whose Start() failed","Enable/start the required dependency plugin first, or add it to the configuration","Fix the root cause in the dependency plugin (config, external service, resource availability)","If the dependency is optional, remove it from the plugin's dependsOn list"],"exampleFix":"// before (config)\nplugins: {\"whiteboard\": {\"enabled\": true}, \"chat\": {\"enabled\": false}}\n// after (chat is a whiteboard dependency)\nplugins: {\"whiteboard\": {\"enabled\": true}, \"chat\": {\"enabled\": true}}","handlingStrategy":"try-catch","validationCode":"for _, dep := range plugin.DependsOn() {\n\tif !pm.IsRegistered(dep) {\n\t\treturn fmt.Errorf(\"plugin %s requires dependency %s which is not enabled\", plugin.Name(), dep)\n\t}\n}","typeGuard":"func dependenciesEnabled(deps []string, enabled map[string]bool) bool {\n\tfor _, d := range deps {\n\t\tif !enabled[d] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","tryCatchPattern":"if err := manager.Start(\"whiteboard\"); err != nil {\n\tvar perr *pluginError\n\tif errors.As(err, &perr) && strings.Contains(err.Error(), \"dependency\") {\n\t\tlog.Printf(\"dependency chain failed, disabling plugin: %v\", err)\n\t} else {\n\t\treturn err\n\t}\n}","preventionTips":["Before enabling a plugin in config, verify every plugin in its dependsOn list is also enabled","Use errors.As/errors.Is to unwrap the %w chain to the root cause instead of string matching","Keep dependency lists updated when renaming or removing plugins"],"tags":["plugins","dependency-chain","startup"],"backgroundTag":"plugin-dependency-start-failed","analyzedSha":"b0f01cedea68893e85a3fd852c0521238c285695","analyzedAt":"2026-09-01T10:35:56.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}