hasura/graphql-engine · error
could not uninstall symlink of plugin: %w
Error message
could not uninstall symlink of plugin: %w
What it means
Uninstall() removes the symlink/shim the installer placed in the bin directory (BinPath()/PluginNameToBin(name)) via removeLink. If that removal fails, this error is returned and the plugin directory and receipt are left untouched, so the uninstall is incomplete but restartable.
Source
Thrown at cli/plugins/plugins.go:253
// Uninstall will uninstall a plugin.
func (c *Config) Uninstall(name string) error {
var op errors.Op = "plugins.Config.Uninstall"
if _, err := c.LoadManifest(c.Paths.PluginInstallReceiptPath(name)); err != nil {
if stderrors.Is(err, fs.ErrNotExist) {
return errors.E(op, ErrIsNotInstalled)
}
return errors.E(
op,
fmt.Errorf("failed to look up install receipt for plugin %q: %w", name, err),
)
}
symlinkPath := filepath.Join(c.Paths.BinPath(), PluginNameToBin(name, IsWindows()))
if err := removeLink(symlinkPath); err != nil {
return errors.E(op, fmt.Errorf("could not uninstall symlink of plugin: %w", err))
}
pluginInstallPath := c.Paths.PluginInstallPath(name)
if err := os.RemoveAll(pluginInstallPath); err != nil {
return errors.E(
op,
fmt.Errorf("could not remove plugin directory %q: %w", pluginInstallPath, err),
)
}
pluginReceiptPath := c.Paths.PluginInstallReceiptPath(name)
err := os.Remove(pluginReceiptPath)
if err != nil {
return errors.E(
op,
fmt.Errorf("could not remove plugin receipt %q: %w", pluginReceiptPath, err),
)View on GitHub (pinned to 724551b9ae)
Solutions
- Check what exists at BinPath()/PluginNameToBin(name) (ls -la) — if it is a real file or directory rather than a symlink, remove it manually
- Fix ownership/permissions of the bin directory (chown -R $(whoami) or run once with appropriate privileges) and retry uninstall
- On Windows, ensure no process is running the plugin binary and that the file is not locked
- Re-run Uninstall afterwards — the operation is idempotent once the path is clear
Example fix
# before $ ls -la ~/.cli/bin/myplugin # regular file left by manual copy $ rm ~/.cli/bin/myplugin # after: uninstall succeeds
Defensive patterns
Strategy: try-catch
Validate before calling
binTarget := filepath.Join(cfg.Paths.BinPath(), PluginNameToBin(name, IsWindows()))
if fi, err := os.Lstat(binTarget); err == nil && fi.Mode()&os.ModeSymlink == 0 {
// a real file/dir sits where the symlink should be; remove it first
_ = os.RemoveAll(binTarget)
} Try / catch
if err := cfg.Uninstall(name); err != nil && strings.Contains(err.Error(), "could not uninstall symlink") {
// inspect and remove the path at BinPath manually, then retry Uninstall
} Prevention
- Never replace the generated bin symlink with a copied binary
- Keep bin directory ownership consistent with the user running the CLI
- On Windows, close processes using the plugin binary before uninstalling
When it happens
Trigger: Calling Uninstall when the symlink in the bin directory cannot be removed: permission denied (bin dir owned by root or another user), the path exists but is a real file on Windows where a shim was expected, or the path is a non-empty directory removeLink refuses to delete.
Common situations: CLI was installed via sudo so the bin dir is root-owned; a user replaced the symlink with a real binary; Windows-specific shim/file mismatch; the bin directory is on a read-only mount.
Related errors
- could not remove plugin directory %q: %w
- failed to remove old symlink: %w
- failed to resolve the symlink of the currently executed vers
- failed to look up install receipt for plugin %q: %w
- could not remove plugin receipt %q: %w
AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28).
Data as JSON: /api/errors/34cb7371301962d9.
Report an issue: GitHub.