{"record":{"id":"70df7200ab6637ce","repo":"hasura/graphql-engine","slug":"could-not-remove-plugin-directory-q-w","errorCode":null,"errorMessage":"could not remove plugin directory %q: %w","messagePattern":"could not remove plugin directory %q: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/plugins/plugins.go","lineNumber":260,"sourceCode":"\t\t\treturn errors.E(op, ErrIsNotInstalled)\n\t\t}\n\n\t\treturn errors.E(\n\t\t\top,\n\t\t\tfmt.Errorf(\"failed to look up install receipt for plugin %q: %w\", name, err),\n\t\t)\n\t}\n\n\tsymlinkPath := filepath.Join(c.Paths.BinPath(), PluginNameToBin(name, IsWindows()))\n\tif err := removeLink(symlinkPath); err != nil {\n\t\treturn errors.E(op, fmt.Errorf(\"could not uninstall symlink of plugin: %w\", err))\n\t}\n\n\tpluginInstallPath := c.Paths.PluginInstallPath(name)\n\tif err := os.RemoveAll(pluginInstallPath); err != nil {\n\t\treturn errors.E(\n\t\t\top,\n\t\t\tfmt.Errorf(\"could not remove plugin directory %q: %w\", pluginInstallPath, err),\n\t\t)\n\t}\n\n\tpluginReceiptPath := c.Paths.PluginInstallReceiptPath(name)\n\n\terr := os.Remove(pluginReceiptPath)\n\tif err != nil {\n\t\treturn errors.E(\n\t\t\top,\n\t\t\tfmt.Errorf(\"could not remove plugin receipt %q: %w\", pluginReceiptPath, err),\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc (c *Config) installPlugin(plugin Plugin, platform Platform) error {\n\tvar op errors.Op = \"plugins.Config.installPlugin\"","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/cli/plugins/plugins.go#L242-L278","documentation":"After removing the bin symlink, Uninstall() deletes the plugin's versioned install directory with os.RemoveAll. Any error from that call is returned here, leaving the receipt file still present, so the plugin remains 'installed' from the tool's perspective.","triggerScenarios":"Uninstall fails at os.RemoveAll(PluginInstallPath(name)): permission denied on a file inside the install dir (often a still-executing binary giving ETXTBSY on Linux), read-only filesystem, or the path being held open by another process.","commonSituations":"The plugin process is still running (binary busy, ETXTBSY); install dir owned by root from a previous sudo install; plugins dir on a network/read-only mount; Windows file locking by antivirus or a running shell with cwd inside the dir.","solutions":["Stop any running process using the plugin binary, then retry uninstall","Fix ownership of the plugin install directory (chown -R) or run the uninstall with sufficient privileges","If the directory is on a read-only or locked mount, remount writable / release the lock and retry","As a last resort remove the plugin install directory manually, then remove the leftover receipt file so the plugin no longer appears installed"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"installDir := cfg.Paths.PluginInstallPath(name)\nif err := os.RemoveAll(installDir); err == nil {\n\t// pre-clear the directory so Uninstall's RemoveAll is a no-op\n}","typeGuard":null,"tryCatchPattern":"err := cfg.Uninstall(name)\nif err != nil && strings.Contains(err.Error(), \"could not remove plugin directory\") {\n\t// stop running plugin processes, fix ownership, then retry — the operation is idempotent\n}","preventionTips":["Terminate plugin processes before uninstalling (avoids ETXTBSY on Linux)","Don't keep shells/terminals cd'd into plugin install directories","Avoid mixed sudo/non-sudo installs that leave root-owned files in the install dir"],"tags":["plugins","uninstall","filesystem","permissions"],"backgroundTag":"directory-removal-failed","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}