hasura/graphql-engine · error

could not remove plugin directory %q: %w

Error message

could not remove plugin directory %q: %w

What it means

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.

Source

Thrown at cli/plugins/plugins.go:260

			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),
		)
	}

	return nil
}

func (c *Config) installPlugin(plugin Plugin, platform Platform) error {
	var op errors.Op = "plugins.Config.installPlugin"

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Stop any running process using the plugin binary, then retry uninstall
  2. Fix ownership of the plugin install directory (chown -R) or run the uninstall with sufficient privileges
  3. If the directory is on a read-only or locked mount, remount writable / release the lock and retry
  4. As a last resort remove the plugin install directory manually, then remove the leftover receipt file so the plugin no longer appears installed
Defensive patterns

Strategy: retry

Validate before calling

installDir := cfg.Paths.PluginInstallPath(name)
if err := os.RemoveAll(installDir); err == nil {
	// pre-clear the directory so Uninstall's RemoveAll is a no-op
}

Try / catch

err := cfg.Uninstall(name)
if err != nil && strings.Contains(err.Error(), "could not remove plugin directory") {
	// stop running plugin processes, fix ownership, then retry — the operation is idempotent
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/70df7200ab6637ce. Report an issue: GitHub.