{"record":{"id":"c0ce5da6c77d5f24","repo":"flipped-aurora/gin-vue-admin","slug":"plugin-already-exists","errorCode":null,"errorMessage":"plugin already exists","messagePattern":"plugin already exists","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/auto_code_plugin.go","lineNumber":336,"sourceCode":"\t\treturn \"\", err\n\t}\n\tinfo, err := os.Stat(parentPath)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"parent plugin does not exist\")\n\t}\n\tif !info.IsDir() {\n\t\treturn \"\", errors.New(\"parent plugin is not a directory\")\n\t}\n\treturn utils.JoinWithinRoot(parentPath, \"subPlugin\")\n}\n\nfunc ensurePluginTargetAvailable(root, pluginName string) error {\n\ttarget, err := utils.JoinWithinRoot(root, pluginName)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif _, err = os.Stat(target); err == nil {\n\t\treturn errors.New(\"plugin already exists\")\n\t} else if !os.IsNotExist(err) {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc copyPluginArchive(sourceRoot, destinationRoot string) error {\n\tif err := os.MkdirAll(destinationRoot, 0755); err != nil {\n\t\treturn err\n\t}\n\treturn cp.Copy(sourceRoot, destinationRoot, cp.Options{Skip: skipMacSpecialDocument})\n}\n\nfunc prepareSubPluginSource(childPath, parentPlugin, childPlugin string) error {\n\tmodule := strings.TrimSpace(global.GVA_CONFIG.AutoCode.Module)\n\tif module == \"\" {\n\t\treturn errors.New(\"autocode module is empty\")\n\t}","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/auto_code_plugin.go#L318-L354","documentation":"Before copying the sub-plugin into place, the installer checks that the destination directory (`<root>/<pluginName>`) does not already exist. If os.Stat succeeds, meaning something already occupies the target path, the install is aborted to avoid overwriting an existing plugin.","triggerScenarios":"Installing a sub-plugin whose name already exists under the parent's `subPlugin` directory — either a previous install already placed it, or the user is re-running an install that partially completed, or another plugin happens to use the same name.","commonSituations":"Re-submitting the same install request twice; installing a different version of the same sub-plugin without uninstalling the old one; name collision between two independently developed sub-plugins; leftover folder from a failed prior install that copied files before failing.","solutions":["Remove the existing directory at the target path if it is safe to delete (e.g. old version), then retry the install.","Uninstall the existing sub-plugin through the normal uninstall flow before reinstalling.","Rename the incoming sub-plugin (directory and module references) to a unique name and repackage.","If a previous install partially failed, clean the leftover target directory manually first."],"exampleFix":"// before\nls server/plugin/parent/subPlugin/child  # exists -> error\n// after\nrm -rf server/plugin/parent/subPlugin/child\n# then retry the install API call","handlingStrategy":"validation","validationCode":"const target = path.join(serverPluginRoot, parent, 'subPlugin', child)\nif (fs.existsSync(target)) throw new Error(`sub-plugin target already exists: ${target}`)","typeGuard":null,"tryCatchPattern":"try {\n  await installSubPlugin(parent, child)\n} catch (e) {\n  if (e.message.includes('already exists')) {\n    const ok = await confirm('Remove existing sub-plugin and reinstall?')\n    if (ok) { await uninstallSubPlugin(parent, child); await installSubPlugin(parent, child) }\n  } else { throw e }\n}","preventionTips":["Check whether the sub-plugin is already installed before calling the install API.","Clean up partial installs after any failed operation before retrying.","Use unique, well-namespaced plugin names to avoid collisions."],"tags":["plugin-install","filesystem","conflict"],"backgroundTag":"target-already-exists","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}