hasura/graphql-engine · error
failed to remove old symlink: %w
Error message
failed to remove old symlink: %w
What it means
createOrUpdateLink first removes any existing symlink at dst (filepath.Join(binDir, PluginNameToBin(plugin, IsWindows()))) via removeLink before installing the new one. If removeLink fails — because dst exists as a real file/dir, permissions block unlink, or binDir is not writable — this error wraps the OS failure.
Source
Thrown at cli/plugins/util.go:184
return nil
}
// IsWindows sees runtime.GOOS to find out if current execution mode is win32.
func IsWindows() bool {
goos := runtime.GOOS
return goos == "windows"
}
func createOrUpdateLink(binDir, binary, plugin string) error {
var op errors.Op = "plugins.createOrUpdateLink"
dst := filepath.Join(binDir, PluginNameToBin(plugin, IsWindows()))
err := removeLink(dst)
if err != nil {
return errors.E(op, fmt.Errorf("failed to remove old symlink: %w", err))
}
if _, err := os.Stat(binary); stderrors.Is(err, fs.ErrNotExist) {
return errors.E(
op,
fmt.Errorf(
"can't create symbolic link, source binary (%q) cannot be found in extracted archive: %w",
binary,
err,
),
)
}
// Create new
err = os.Symlink(binary, dst)
if err != nil {
if IsWindows() {
// If cloning the symlink fails on Windows because the userView on GitHub (pinned to 724551b9ae)
Solutions
- Inspect the wrapped OS error (EACCES vs EISDIR vs ENOTDIR) to identify the cause.
- Manually remove the stale entry: rm <binDir>/<plugin-bin> (or rmdir if it's a directory).
- Ensure binDir is writable by the current user (chown/chmod), or configure a user-local bin dir.
Example fix
# before $ ls ~/.cli/bin/myplugin # regular file from old manual install # install fails: failed to remove old symlink # after $ rm ~/.cli/bin/myplugin $ cli plugin install myplugin
Defensive patterns
Strategy: try-catch
Validate before calling
dst := filepath.Join(binDir, pluginBinaryName)
if fi, err := os.Lstat(dst); err == nil && fi.Mode()&os.ModeSymlink == 0 {
// a real file/dir occupies the link path — remove or relocate it first
if err := os.RemoveAll(dst); err != nil {
return err
}
} Try / catch
if err := plugins.Install(...); err != nil {
if errors.Is(err, fs.ErrPermission) && strings.Contains(err.Error(), "remove old symlink") {
// instruct user to fix bin dir permissions or remove stale file
}
} Prevention
- Keep the CLI bin dir owned by the invoking user; avoid mixing sudo and non-sudo installs.
- Never manually copy plugin binaries into the managed bin dir.
- On install failures, clean the stale link target and re-run install.
When it happens
Trigger: installPlugin → createOrUpdateLink where binDir/<plugin>(.exe) exists as a non-symlink file, or the user lacks write permission on binDir, so os.Remove/os.Lstat in removeLink returns an error.
Common situations: A previous manual copy of the binary into the bin dir; a directory sitting where the link should go; bin dir owned by root after sudo installs; Windows/WSL path quirks.
Related errors
- could not create staging dir %q: %w
- failed to ensure create directory %q: %w
- failed to resolve the symlink of the currently executed vers
- installation receipt could not be stored, uninstall may fail
- could not uninstall symlink of plugin: %w
AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28).
Data as JSON: /api/errors/3a15065e03af3d53.
Report an issue: GitHub.