Why sudo says command not found — even though the command works without sudo

A strange picture:
npm -v
# 10.9.2
sudo npm -v
# sudo: npm: command not found
npm was just there. You added one word — and it's gone. As if sudo were looking at a different computer.
That's almost the case. sudo runs the command not in your environment, but in a clean, stripped-down one. It's protection, not a bug. Below are five causes people trip over most — from most common to rarest.
Cause 1. sudo has its own PATH
When you type npm, the shell looks for the program in the folders from your PATH variable. Yours includes, say, ~/.nvm/versions/node/v22/bin — that's where the nvm manager installed Node.
But sudo throws your PATH away. In its place it uses secure_path — a short list of system folders from sudo's settings. Your nvm folder isn't there. Hence command not found.
How to check:
sudo grep secure_path /etc/sudoers
# Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
which npm
# /home/me/.nvm/versions/node/v22.11.0/bin/npm
If the folder from which isn't in secure_path — that's it.
How to fix:
- Best option — drop the sudo. With nvm, pyenv, Homebrew and the like, global packages install into your home folder. They don't need root.
npm install -gwithout sudo is correct, not a mistake. - If you truly need root — pass your PATH explicitly:
sudo env "PATH=$PATH" npm install. - The full path
sudo "$(which npm)"won't save you here. npm itself callsnode— and looks for it in the stripped PATH again. For ordinary programs without such dependencies, the full path works.
Editing secure_path in /etc/sudoers for a single program isn't worth it: a mistake in that file can lock you out of sudo entirely.
Cause 2. sudo resets variables
The variable is set, the program doesn't see it:
export API_KEY=abc123
sudo python deploy.py
# KeyError: 'API_KEY'
That's the env_reset setting: by default sudo clears almost all environment variables. Otherwise you could slip something dangerous to a root program through them.
How to check:
X=hi sudo sh -c 'echo "[$X]"'
# []
Empty brackets — the variable didn't make it.
How to fix:
- Pass one variable:
sudo API_KEY="$API_KEY" python deploy.py. The cleanest way. - Keep the whole environment:
sudo -E python deploy.py. Works, but drags everything under root — better one at a time.
Cause 3. Permission denied when writing to a file
A different error here, but just as surprising:
sudo echo "127.0.0.1 myapp.local" >> /etc/hosts
# bash: /etc/hosts: Permission denied
But you wrote sudo! Yet sudo only received echo "...". The >> arrow is run by your shell, before sudo even starts, with your normal rights. Root printed the line, but a non-root shell tried to write it to the file.
How to fix: hand the writing to a program that runs as root.
echo "127.0.0.1 myapp.local" | sudo tee -a /etc/hosts
tee with -a appends to the end of the file, and it runs through sudo. To write many lines at once, sudo tee pairs nicely with a heredoc. Another option — wrap the whole command: sudo sh -c 'echo "..." >> /etc/hosts'.
Cause 4. Aliases don't work after sudo
You have an alias ll for ls -la. You type sudo ll — and get command not found.
The shell expands an alias only for the first word of a command. Here the first word is sudo, and the shell doesn't check ll. And sudo itself knows nothing about your aliases: they live in your shell settings, not in the system.
How to fix: add one line to ~/.bashrc or ~/.zshrc:
alias sudo='sudo '
The trailing space is the trick. If an alias value ends with a space, the shell checks the next word for an alias too. Now sudo ll works.
Cause 5. sudo cd and other built-in commands
sudo cd /root
# sudo: cd: command not found
cd, source, export, alias aren't programs on disk. They're commands inside the shell itself. No PATH will find them, because there's no separate file. And sudo can only run files.
Recent versions of sudo even hint at it right in the error: "is a shell built-in command".
How to fix: if you need to work in a locked folder, open a whole root shell — sudo -s — and leave with exit when you're done. For one command, sudo sh -c 'cd /root && ls' is enough: here a shell starts as root and runs cd itself.
Quick diagnosis
Something broke under sudo — go down the list:
command not found→ comparewhich commandwith secure_path. Most likely sudo isn't needed at all.- The program doesn't see a variable → pass it explicitly:
sudo VAR="$VAR" command. Permission deniedwith>or>>→ replace it with| sudo tee.- An alias doesn't work →
alias sudo='sudo '. sudo cdorsudo source→ these are built-ins, usesudo -sorsudo sh -c '...'.
Can I just do everything via sudo su?
You can, but it's like walking around the house with keys to every door. One typo — and root deletes the wrong thing. Raise your rights for one command, not for the whole session.
Why doesn't my Mac have this problem?
On macOS, sudo keeps your PATH by default, so the first cause rarely shows up there. The other three — reset variables, redirection and aliases — work the same as on Linux.
Short story-lessons, an agent simulator and daily practice — in our mobile app. Free.





