Permission denied and exit codes 126 / 127 — command will not run
127 means the shell could not find the command; 126 means it found it but could not run it, usually 'Permission denied'.
What happened
A command or script in a shell, a CI pipeline step or a cron job failed before it did any work. The shell printed an error and set the exit status to 127 or 126.
$ mpzip --all bash: mpzip: command not found $ echo $? 127 $ ./mpload.sh bash: ./mpload.sh: Permission denied $ echo $? 126
What it means
In Bash, 0 means success and any non-zero value means failure; $? holds the status of the last command. Values above 125 have special meanings:
- 127 — the command was not found: no function, builtin or file with that name in the directories listed in
PATH. - 126 — the command was found but is not executable.
- 128 + N — the command was killed by signal N (for example 137 = killed by signal 9).
- 2 — a builtin was used incorrectly (bad option or missing argument).
Behind 'Permission denied', the kernel's execve() call failed with EACCES. The man page lists the cases: the file lacks execute permission, a directory in the path does not allow search, the file is not a regular file, or the filesystem is mounted noexec. If a script's #! interpreter path does not exist, execve() fails with ENOENT instead.
Typical causes
- 127 — a typo, a tool not installed in this image or agent, or
PATHdifferent in cron or CI than in your login shell. - 126 — a script checked out or copied without its execute bit; a script on a
noexecmount such as some /tmp setups; trying to run a directory. - A
#!line pointing to an interpreter that does not exist on this machine.
Symptoms
- Works on your laptop, fails on the build agent or server.
- Works when called as
bash script.sh, fails when called as./script.sh— the execute bit or the interpreter line is the problem.
Where to look
echo $?straight after the failure.ls -lon the file for thexpermission bits and owner, andls -ldon each parent directory.echo $PATHandcommand -v name(ortype name) in the same environment that failed.head -1 scriptfor the interpreter line, andmountoutput fornoexec.
How to diagnose
- Note the exit status: 127 or 126.
- For 127, check spelling, check the tool is installed, and compare
PATHin the failing environment. - For 126, check the execute bit with
ls -l, then directory search permission, then the mount options. - Check the
#!line points at a real interpreter on this machine.
How to fix
- Add execute permission for the right users, e.g.
chmod u+x mpload.sh— neverchmod 777. - In Git, record the execute bit so every checkout gets it:
git update-index --chmod=+x mpload.sh. - Use the full path, or set
PATHexplicitly in cron jobs and pipeline steps. - Install the missing tool in the image or agent, through the normal build of that image.
- Move scripts off
noexecfilesystems, or run them via the interpreter if your standards allow.
How to prevent
- Set
PATHat the top of scripts that run unattended. - Check required tools at the start of a pipeline and fail with a clear message.
- Use
#!/usr/bin/env bashor the path your platform standard requires, consistently.
Production considerations
Interview question
A pipeline step fails with exit code 127. What do you check?
Stuck on something else?
Ask the community or search the full course.