Skip to content
Latchkey

GitHub Actions run step "Permission denied" running a script

The runner tried to exec a script directly but the file is not marked executable. Git does not always preserve the executable bit, so a script that runs locally can fail in CI.

What this error means

A run step that calls a local script with "./script.sh" fails with "Permission denied" and exit code 126.

github-actions
/usr/bin/bash: line 1: ./scripts/deploy.sh: Permission denied
##[error]Process completed with exit code 126.

Common causes

Executable bit not committed

The script was added without "git update-index --chmod=+x", so its mode is 100644 in the repo and the runner cannot exec it.

Script created at runtime without chmod

A step wrote the script file but never set the +x bit before invoking it directly.

How to fix it

Invoke through the interpreter

  1. Call the script with an explicit interpreter so the executable bit is irrelevant.
  2. Re-run; bash reads the file without needing exec permission.
.github/workflows/ci.yml
- run: bash ./scripts/deploy.sh

Set the executable bit in git

  1. Mark the script executable in the index and commit it.
  2. Verify with "git ls-files -s scripts/deploy.sh" that the mode is 100755.
  3. Now "./scripts/deploy.sh" works on the runner.
local shell
git update-index --chmod=+x scripts/deploy.sh
git commit -m "make deploy.sh executable"

How to prevent it

  • Commit shell scripts with the executable bit set, or always invoke them via bash/sh.
  • Add a CI lint that flags checked-in *.sh files missing the +x mode.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →