Skip to content
Get started

Exit code 127: command not found (a cron PATH problem)

Exit code 127 means the shell could not find the command it was asked to run. In a cron job this is almost always a PATH problem: cron runs with a minimal environment and a short PATH, so a command that works in your interactive shell (like aws, node, or python3) isn't found when cron runs it. The fix is to call the command by its absolute path or set PATH explicitly at the top of the script.

Why do I get exit code 127 only in cron?

cron does not run your job in a login shell. It runs with a deliberately minimal environment — a short PATH (often just /usr/bin:/bin), no profile, and few of the variables your interactive shell sets up. A tool installed in /usr/local/bin or a language version manager's shim directory is on your PATH interactively but not on cron's PATH, so the shell can't locate it and returns 127.

The tell is a message like `aws: command not found` or `node: command not found` in the job's output, followed by exit status 127.

How do I fix exit code 127 in a cron job?

Option 1: call the command by absolute path

# Find the absolute path in your interactive shell:
which aws        # e.g. /usr/local/bin/aws

# Use that absolute path in the cron job / script:
/usr/local/bin/aws s3 cp backup.sql.gz s3://bucket/

Option 2: set PATH at the top of the script

backup.sh
#!/usr/bin/env bash
set -euo pipefail
export PATH="/usr/local/bin:/usr/bin:/bin:$PATH"

aws s3 cp backup.sql.gz s3://bucket/
Add `set -euo pipefail` so the script stops on the first error instead of continuing past a failed command and printing a misleading "done". A job that ignores the 127 and prints success is the silent-failure class a monitor exists to catch.

What's the difference between exit 127 and exit 126?

127 means the command was not found at all. 126 means the command was found but could not be executed — usually because the file is not executable (a missing chmod +x) or a directory was named where a program was expected. If you get 126, check the file's permissions and that it has a valid interpreter line.

How do I get alerted when a cron job exits 127?

A 127 means the real work never ran, but the surrounding script may still exit cleanly and even print success. Ping the monitor only when the whole script succeeds under `set -e`, so a 127 that aborts the script withholds the ping and triggers the alert:

#!/usr/bin/env bash
set -euo pipefail
export PATH="/usr/local/bin:/usr/bin:/bin:$PATH"

/usr/local/bin/aws s3 cp backup.sql.gz s3://bucket/
# Only reached if every command above succeeded.
curl -fsS -m 10 --retry 3 "https://ping.cronshield.com/<your-check-id>"
On paid tiers, CronShield reads the failing run's output and puts the `command not found` line and a likely cause (a cron PATH gap) in the alert. PING_URL is a placeholder for the endpoint you get on a monitor.

Catch this failure automatically

The free tier gives you a heartbeat endpoint and an email alert when an expected ping doesn't arrive. Paid tiers add the log-aware diagnosis — the last log line and a likely cause in the alert. The heartbeat receiver ships in an upcoming release; see the plans to learn what each tier adds.

Frequently asked questions

Why does my script work manually but fail with 127 in cron?
Because cron runs with a minimal PATH that doesn't include directories like /usr/local/bin or a version manager's shims where your tool lives. Interactively your shell profile adds those to PATH; cron doesn't load your profile. Use an absolute path or set PATH in the script.
Does exit 127 mean the whole job failed?
It means one command wasn't found. Whether the job as a whole fails depends on your error handling: without `set -e`, the script keeps going after the missing command and may exit 0, hiding the failure. Add `set -euo pipefail` so a 127 aborts the run loudly.