Linux / shell
Permission denied on exec — which permission actually failed?
Written and reviewed by Sahil Srivastav
bash: ./deploy.sh: Permission deniedWhat this error actually means
Executing a file requires more than permission to read its bytes. The process needs directory search permission along the path, an executable target, and an execution policy that allows the operation. For a script, the interpreter named in the shebang must also be accessible and executable. The shell can report the same Permission denied message for several different failures in this chain.
This is why chmod +x sometimes helps and sometimes changes nothing. Mode bits are only one decision point. A filesystem mounted with noexec can reject direct execution even when ls shows executable bits. ACLs or a security policy can also deny the service account access that succeeds for your own account.
Diagnose from the identity and mount namespace of the failing process. A host path and the same-looking path inside a container may have different mounts and permissions. Checking as root in an interactive terminal can hide the exact restriction the application encountered.
Causes, most common first
- 1The executable bit was lost during packaging or copying. A source archive, checkout or file-copy step can produce a readable script without execute permission. Confirm the mode on the deployed artifact, not only on the source file. An interpreter can read such a script when explicitly invoked, masking the packaging defect.
- 2A parent directory or interpreter is inaccessible. Directory execute permission means traversal. A file can have mode 755 while a parent directory blocks the service account. The same issue can affect the shebang interpreter, especially when it lives below another user’s home directory.
- 3The filesystem prohibits direct execution. Temporary, shared or container-mounted filesystems may be mounted noexec. Changing the target’s mode cannot override that mount option. Move the executable to the intended application location instead of broadly weakening a mount’s policy.
- 4An ACL or security policy denies the operation. After ordinary modes and mount flags are ruled out, inspect effective ACLs and the host’s security audit records. A policy denial needs a narrow policy or labelling correction; making every file world-writable is unrelated to the execution check.
When you see it
- The script is readable but ./script.sh fails before its first log line
- bash script.sh works while direct execution fails
- The same artifact executes from /opt but fails from a mounted workspace
- Only a service account fails, despite apparently correct file mode bits
How to diagnose it
Step 1
Check every path component
On Linux with util-linux installed, namei shows permissions along the resolved path. Run id in the failing context and compare the account’s groups with the directory and file owners. Replace the example with the deployed file.
id
namei -l /srv/app/deploy.sh
ls -l /srv/app/deploy.shStep 2
Read the shebang without executing anything
Confirm the interpreter path, then inspect that path with namei too. A shebang pointing at an unavailable interpreter usually yields a missing-file error; an interpreter that exists but cannot be executed can yield a permission error.
head -n 1 /srv/app/deploy.sh
namei -l /bin/bashStep 3
Inspect the mount that contains the script
Use findmnt inside the same container or namespace as the failure. Look for noexec in the options. The target path matters: checking only the root filesystem misses a separate mount on a subdirectory.
findmnt -T /srv/app/deploy.sh -o TARGET,FSTYPE,OPTIONSStep 4
Check ACLs after the basic checks
Where POSIX ACL tools are installed, getfacl shows named-user rules and the mask limiting effective permissions. For SELinux or AppArmor systems, correlate security audit denials with the exact execution timestamp before changing policy.
getfacl /srv /srv/app /srv/app/deploy.shThe fix
If only the owner needs to execute the script, restore that bit with chmod u+x on the specific artifact. If the service runs as a different account, give the intended group traversal and execution access as part of packaging. Choose ownership and modes deliberately; chmod 777 adds write access and does not solve mount or policy restrictions.
Use a shebang whose interpreter is present in the deployed image. Preserve executable mode in the source repository and release artifact. Recheck the actual installed copy after deployment because the copy step may be the component that strips the bit.
For noexec, install the application on an execution-enabled filesystem approved for application binaries. Calling bash script.sh can help isolate the difference between reading and direct execution, but it does not establish that a restricted mount is an appropriate application location. For an ACL or policy failure, fix the specific account, path or label and repeat the execution as that account.
# After proving the missing owner execute bit is the cause:
chmod u+x /srv/app/deploy.sh
# Re-run from the same account and namespace as the original failure.
/srv/app/deploy.shHow to stop it coming back
- Verify artifact modes and the shebang interpreter in the built container or installed release, rather than only in the source checkout.
- Run deployment smoke checks as the service account; root checks can conceal missing directory traversal permissions.
- Document where executable artifacts belong so temporary and data mounts do not become accidental runtime locations.
FAQ
Why can I read the script but not execute it?
Read permission lets an interpreter consume the file as data. Direct execution asks the kernel to execute it and applies additional checks. Successful cat output therefore proves only that the current account can read the file.
Should I run the script with sudo?
Changing identity can mask incorrect ownership and introduce different environment inputs. First identify the denied path and intended account. If the application is designed to run unprivileged, repair that access path and verify it without elevated privileges.
Is a bad shebang always Permission denied?
No. A nonexistent interpreter commonly produces a missing-file error, while a wrong executable format has another failure. Preserve the original error text; these distinctions help separate permissions from line endings and image architecture.
Related
Other errors engineers hit next to this one
- InterruptedException caught and ignored — the task can no longer be cancelled
- Two unrelated components sharing a monitor via a boxed Integer or interned String
- Cache stampede — the same expensive value built many times concurrently
- Lock convoy — throughput collapses as threads are added, with no deadlock
- ReadWriteLock writer blocked indefinitely behind a stream of readers
- Worker loop never sees the stop flag and runs forever
- psycopg2.InterfaceError: connection already closed
- RecursionError: maximum recursion depth exceeded