Uninstalling Docker Desktop Leaves Dangling Symlinks in /usr/local/bin¶
Dragging Docker.app to the Trash removes the application but not the CLI shims it installed. What's left is a set of dangling symlinks pointing into a bundle that no longer exists:
Note the error names a path that is in PATH — this is not "command not found". The symlink resolves, its target doesn't.
The Short Answer¶
# See what's actually broken (dangling symlinks only):
find /usr/local/bin -type l ! -exec test -e {} \; -print
# Remove Docker Desktop's shims (root-owned, needs sudo):
sudo rm -f /usr/local/bin/docker /usr/local/bin/docker-compose \
/usr/local/bin/docker-credential-desktop \
/usr/local/bin/docker-credential-ecr-login \
/usr/local/bin/docker-credential-osxkeychain \
/usr/local/bin/kubectl /usr/local/bin/kubectl.docker
# Leftover config (contexts, buildx state, credential helper settings):
rm -rf ~/.docker
Check ~/.docker/config.json before deleting if you ever logged into a registry or defined remote contexts — see below.
Don't Forget kubectl¶
Docker Desktop installs kubectl and kubectl.docker into the same directory. These are easy to miss because they aren't obviously Docker-named, and a broken kubectl will look like an unrelated Kubernetes problem later:
$ ls -l /usr/local/bin/kubectl
lrwxr-xr-x 1 root wheel 55 Aug 4 20:50 /usr/local/bin/kubectl -> /Applications/Docker.app/Contents/Resources/bin/kubectl
If you use kubectl from Homebrew, removing the Docker shim is required for the real one to take precedence anyway.
Check ~/.docker Before Deleting It¶
Usually disposable, occasionally not. Two things worth a look:
cat ~/.docker/config.json # registry logins
find ~/.docker/contexts -name meta.json -exec cat {} \; # remote contexts
auths— if non-empty, you have stored registry credentials. Deleting is still fine (you'll re-authenticate), but know that you are discarding them.- contexts — a context pointing at a remote Docker host (over SSH or TCP) is real configuration worth keeping if you'll use
dockeragain from another install. A lonedesktop-linuxcontext pointing at a local socket is dead weight once the app is gone.
Why sudo Is Needed — and Why It May Fail in an Agent Shell¶
The symlinks are root:wheel in a root-owned directory, so removal needs sudo. In a non-interactive shell — an AI coding agent, a CI job, an ssh host 'cmd' invocation — sudo cannot prompt:
sudo: a terminal is required to read the password; either use the -S option
to read from standard input or configure an askpass helper
Prefixing the command to run it in the calling terminal usually doesn't help either, because that shell is typically not a TTY. On macOS, the reliable workaround is to let the system present a GUI authentication dialog:
osascript -e 'do shell script "rm -f /usr/local/bin/docker /usr/local/bin/kubectl" with administrator privileges'
You authenticate in the standard macOS prompt; no password passes through the shell.
Verifying You're Actually Clean¶
ls -l /usr/local/bin/ # nothing pointing into /Applications/Docker.app
ls -d /Applications/Docker.app ~/.docker 2>&1
which -a docker docker-compose kubectl
brew list --cask | grep -i docker
brew list --formula | grep -iE "docker|colima|podman|lima"
A clean machine returns no Docker entries from any of these. If you removed Docker in favour of another runtime, remember the replacement (colima, podman, OrbStack, Rancher Desktop) provides its own docker shim — install it after clearing the dangling ones, or the stale symlink can shadow it.
Related¶
- /usr/local/sbin Is a Symlink: The 'Duplicate' Script That Was One File — another
/usr/localsymlink surprise - A GUI App's CLI May Not Share Its Name — the reverse problem: bundle-backed CLI symlinks that are alive and easy to overlook