{"record":{"id":"4193dfc77fbb6026","repo":"gotify/server","slug":"plugin-with-module-path-s-is-present-at-least-twi","errorCode":null,"errorMessage":"plugin with module path %s is present at least twice","messagePattern":"plugin with module path (.+?) is present at least twice","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/manager.go","lineNumber":252,"sourceCode":"\t\tif err != nil {\n\t\t\treturn pluginFileLoadError{name, err}\n\t\t}\n\t\tcompatPlugin, err := compat.Wrap(pRaw)\n\t\tif err != nil {\n\t\t\treturn pluginFileLoadError{name, err}\n\t\t}\n\t\tif err := m.LoadPlugin(compatPlugin); err != nil {\n\t\t\treturn pluginFileLoadError{name, err}\n\t\t}\n\t}\n\treturn nil\n}\n\n// LoadPlugin loads a compat plugin, exported to sideload plugins for testing purposes.\nfunc (m *Manager) LoadPlugin(compatPlugin compat.Plugin) error {\n\tmodulePath := compatPlugin.PluginInfo().ModulePath\n\tif _, ok := m.plugins[modulePath]; ok {\n\t\treturn fmt.Errorf(\"plugin with module path %s is present at least twice\", modulePath)\n\t}\n\tm.plugins[modulePath] = compatPlugin\n\treturn nil\n}\n\n// InitializeForUserID initializes all plugin instances for a given user.\nfunc (m *Manager) InitializeForUserID(userID uint) error {\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\n\tuser, err := m.db.GetUserByID(userID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif user != nil {\n\t\treturn m.initializeForUser(*user)\n\t}\n\treturn fmt.Errorf(\"user with id %d not found\", userID)","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/gotify/server/blob/14bfc256276775c425f988d621dccfe705de18ac/plugin/manager.go#L234-L270","documentation":"LoadPlugin registers a compat plugin keyed by its PluginInfo().ModulePath. Since m.plugins is a map, duplicate module paths would silently overwrite, so loading a second plugin with an already-registered module path returns this error instead.","triggerScenarios":"Calling LoadPlugin (directly or via loadPlugins) with two plugin files that declare the same ModulePath — e.g. the same plugin .so copied under two filenames in the plugin directory.","commonSituations":"Docker images containing both foo.so and foo-v2.so built from the same module, or sideloading a test plugin that duplicates a production plugin.","solutions":["Remove the duplicate .so file from the plugin directory","Ensure each plugin's ModulePath in its PluginInfo is unique","Keep only one version of each plugin on disk"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"paths := map[string]bool{}\nfor _, f := range pluginFiles {\n    compat, err := load(f)\n    if err != nil { continue }\n    mp := compat.PluginInfo().ModulePath\n    if paths[mp] {\n        log.Printf(\"duplicate module path %s in %s\", mp, f)\n        continue\n    }\n    paths[mp] = true\n}","typeGuard":null,"tryCatchPattern":"if err := mgr.LoadPlugin(cp); err != nil {\n    if strings.Contains(err.Error(), \"present at least twice\") {\n        log.Printf(\"skipping duplicate plugin: %v\", err)\n        return nil\n    }\n    return err\n}","preventionTips":["Keep only one .so per module in the plugin directory","Give each plugin a unique ModulePath","Clean old plugin versions before deploying new ones"],"tags":["plugin","duplicate","configuration"],"backgroundTag":"duplicate-plugin-registration","analyzedSha":"14bfc256276775c425f988d621dccfe705de18ac","analyzedAt":"2026-09-05T12:52:36.781Z","contentChangedAt":"2026-09-05T12:52:36.781Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}