{"record":{"id":"4063a67030325fc3","repo":"flipped-aurora/gin-vue-admin","slug":"error-4063a6","errorCode":null,"errorMessage":"删除前端插件目录失败","messagePattern":"删除前端插件目录失败","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/auto_code_plugin.go","lineNumber":923,"sourceCode":"\tvar webDir, serverDir string\n\tif pluginType == \"web\" || pluginType == \"full\" {\n\t\twebDir, err = pluginPath(global.GVA_CONFIG.AutoCode.Web, pluginName)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif pluginType == \"server\" || pluginType == \"full\" {\n\t\tserverDir, err = pluginPath(global.GVA_CONFIG.AutoCode.Server, pluginName)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// 1. 删除前端代码\n\tif pluginType == \"web\" || pluginType == \"full\" {\n\t\terr = os.RemoveAll(webDir)\n\t\tif err != nil {\n\t\t\treturn errors.Wrap(err, \"删除前端插件目录失败\")\n\t\t}\n\t}\n\n\t// 2. 删除后端代码\n\tif pluginType == \"server\" || pluginType == \"full\" {\n\t\terr = os.RemoveAll(serverDir)\n\t\tif err != nil {\n\t\t\treturn errors.Wrap(err, \"删除后端插件目录失败\")\n\t\t}\n\n\t\t// 移除注册\n\t\tif err = removePluginRegisterImport(pluginName); err != nil {\n\t\t\treturn errors.Wrap(err, \"移除插件注册失败\")\n\t\t}\n\t}\n\n\t// 通过utils 获取 api 菜单 字典\n\tapis, menus, dicts := pluginUtils.GetPluginData(pluginName)","sourceCodeStart":905,"sourceCodeEnd":941,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/auto_code_plugin.go#L905-L941","documentation":"In AutoCodePluginService.Remove, when a plugin is being uninstalled with type 'web' or 'full', os.RemoveAll(webDir) deletes the plugin's frontend directory. If the OS-level removal fails (permissions, file locks, path issues), the underlying error is wrapped with '删除前端插件目录失败' and returned, aborting the uninstall.","triggerScenarios":"Calling the plugin removal API (Remove) for a web or full plugin when webDir cannot be deleted: insufficient write permission on web/src/plugin/<name> or its parent, a process (editor, dev server, Windows file lock) holding files open, or a read-only filesystem.","commonSituations":"Running the server on Windows while Vite/IDE keeps files locked; deploying with a read-only web directory or non-root user lacking ownership; webDir path misconfigured via AutoCode config pointing to a nonexistent or protected location.","solutions":["Close programs locking the directory (IDE, vite dev server) and retry the removal","Check and fix filesystem permissions on web/src/plugin/<pluginName> (chown/chmod)","Verify the frontend path is writable by the server process user","If the directory is already gone, remove it manually and re-run removal, or check err to distinguish NotFound","On Windows, ensure antivirus/indexing is not holding handles during removal"],"exampleFix":"// before (permissions issue)\nos.RemoveAll(webDir) // permission denied\n// after (shell)\nsudo chown -R $(whoami) web/src/plugin && retry removal","handlingStrategy":"validation","validationCode":"// Go: check writability before calling remove\nwebDir := filepath.Join(\"web/src/plugin\", pluginName)\nif _, err := os.Stat(webDir); err == nil {\n    if err := unix.Access(webDir, unix.W_OK); err != nil {\n        return fmt.Errorf(\"web plugin dir not writable: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"// Go: inspect the wrapped error to distinguish not-found vs permission\nerr := pluginSvc.Remove(ctx, pluginName, \"web\")\nif err != nil && strings.Contains(err.Error(), \"删除前端插件目录失败\") {\n    if os.IsPermission(errors.Unwrap(err)) { /* fix perms or abort */ }\n    if errors.Is(errors.Unwrap(err), fs.ErrNotExist) { /* already removed: proceed */ }\n}","preventionTips":["Run the server as a user owning web/src/plugin","Stop vite dev server / IDE file watchers before uninstalling plugins","Check directory writability in CI before automated plugin removal","On Windows, exclude the project from antivirus file locking"],"tags":["filesystem","plugin-management","go","os-removeall"],"backgroundTag":"file-delete-permission-denied","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}