Linux Cron Job Not Running: `env PATH` Variable Syntax Error on Ubuntu 20.04 LTS Troubleshooting Guide
Diagnose and resolve 'command not found' errors in Linux cron jobs on Ubuntu 20.04 LTS due to incorrect PATH environment variable configuration.
Diagnose and resolve 'command not found' errors in Linux cron jobs on Ubuntu 20.04 LTS due to incorrect PATH environment variable configuration.
Cron jobs are the backbone of automated task execution on Linux systems, powering everything from database backups to log rotation and application maintenance scripts. However, a common pitfall encountered by both new and experienced administrators is a cron job failing to run, often silently, with symptoms pointing to commands not being found, even though they execute perfectly from an interactive shell. This guide specifically addresses issues on Ubuntu 20.04 LTS related to the PATH environment variable, including potential syntax errors when attempting to configure it within cron, leading to the dreaded "command not found" error.
Symptom & Error Signature
The primary symptom is that your scheduled task simply does not execute or fails with an error indicating that a command within your script cannot be found. You won't typically see a direct "PATH variable syntax error" message unless you've explicitly introduced one while trying to fix the PATH. Instead, the underlying issue (an insufficient PATH) manifests as:
Email Notifications (if
MAILTOis configured):Subject: Cron <user@hostname> /path/to/your/script.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Cron-Env: <SHELL=/bin/sh> X-Cron-Env: <HOME=/home/user> X-Cron-Env: <PATH=/usr/bin:/bin> X-Cron-Env: <LOGNAME=user> X-Cron-Env: <USER=user> Message-Id: <...> Date: Mon, 9 Aug 2026 00:00:00 +0000 (UTC) /path/to/your/script.sh: line 5: some_command: command not foundNote the
X-Cron-Env: <PATH=/usr/bin:/bin>line, indicating a very minimalPATH.System Logs (
/var/log/syslog): You might see entries indicating the cron job started, but no successful completion or specific error messages withinsyslogitself, as the output is usually redirected or mailed.Aug 9 00:00:00 hostname CRON[12345]: (user) CMD (/path/to/your/script.sh) Aug 9 00:00:00 hostname CRON[12344]: (user) END_CMD (/path/to/your/script.sh)The actual
command not founderror would be in the email or a file if output was redirected.No visible output or job execution: The most insidious symptom is simply the absence of the expected outcome (e.g., website data not updated, backups not created) without any obvious error messages.
Root Cause Analysis
The core of this problem lies in the fundamentally different environment in which cron jobs execute compared to your interactive shell.
Minimal
PATHEnvironment: When you log into an interactive shell (e.g., via SSH), yourPATHenvironment variable is typically populated by configuration files like/etc/profile,~/.bashrc,~/.profile, etc. ThisPATHincludes directories where various commands (likenpm,php,python3,composer,wp,docker, custom binaries) are located. Cron, however, runs jobs in a very minimal, non-interactive shell environment (/bin/shor/bin/bashwithout loading user-specific startup files). Its defaultPATHis extremely limited, often just/usr/bin:/binor/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin. If your script tries to call a command not in these default directories (e.g.,phpfrom/usr/local/php8.2/bin,nodefrom~/.nvm/versions/node/vX.Y.Z/bin, ordockerwhich might be in/usr/binbut relies on other environment variables), cron will fail to find it.Lack of Environment Inheritance: Cron jobs do not inherit environment variables from the user's interactive session. This means any
PATHmodifications, custom variables, or aliases defined in your~/.bashrcor~/.profileare completely ignored by cron.PATHSyntax Errors in Crontab: While not a direct error code, users attempting to fix thePATHissue often introduce syntax errors when trying to set thePATHvariable directly within thecrontabentry itself. Common mistakes include:- Using
export PATH="..."directly on the command line of a cron job entry (theexportkeyword is generally unnecessary and sometimes problematic in a single-line crontab command). - Incorrectly expanding existing
PATHvariables within a single line (e.g.,PATH=$PATH:/new/path; command). WhilePATH=/new/path:$PATHcan work when defined at the top of thecrontab, doing it inline can be tricky. - Using unquoted paths with spaces (though less common in
PATHitself). - Typographical errors or incorrect colon separators.
- Using
The solution involves explicitly providing cron with the necessary PATH information, either directly in the crontab or via a wrapper script.
Step-by-Step Resolution
Here's how to systematically troubleshoot and resolve PATH issues for cron jobs on Ubuntu 20.04 LTS.
1. Verify Cron Execution & Capture Output
First, ensure cron is running your job at all, and direct its output for inspection.
Check System Logs:
grep CRON /var/log/syslog | tail -n 50Look for entries related to your user and command. This confirms if cron tried to run your job.
Redirect Cron Job Output: Modify your crontab entry to explicitly redirect all output (stdout and stderr) to a log file. This is crucial for debugging.
# Original (failing) entry example: # * * * * * /path/to/your/script.sh # Modified entry to capture output: * * * * * /path/to/your/script.sh >> /var/log/my_cron_job.log 2>&1After the next scheduled run, check
/var/log/my_cron_job.logfor specific errors likecommand not found.Configure
MAILTO: If you haven't already, add aMAILTOvariable at the top of your user'scrontabto receive error messages directly via email (assuming your system'smaildaemon is configured).MAILTO="[email protected]" # ... rest of your crontab entries ...On Ubuntu, you might need to install a mail client like
mailutils(sudo apt install mailutils) and configure a local MTA (e.g., Postfix) to send external emails. For simple local debugging,MAILTO="youruser"will send mail to your local Linux user.
2. Understand Cron's Default Environment
Let's see exactly what PATH cron is using.
- Create a Temporary Cron Job:
Add a temporary entry to your
crontab(usingcrontab -e) to output cron's environment variables to a file:* * * * * env > /tmp/cron_env.log 2>&1 - Inspect the Output:
Wait a minute, then check the contents of
/tmp/cron_env.log:
You'll likely see a very minimalcat /tmp/cron_env.logPATHlike:
Compare thisSHELL=/bin/sh PWD=/home/youruser LOGNAME=youruser HOME=/home/youruser LANG=en_US.UTF-8 PATH=/usr/bin:/bin _=/usr/bin/envPATHwith your interactive shell'sPATH:
You'll notice the interactive shell'secho $PATHPATHis much richer.
3. Best Practice: Use Absolute Paths
The simplest and most robust fix for command not found is to always use the absolute path to executables within your cron job or script.
- Find the Absolute Path:
In your interactive shell, use the
whichcommand to find the absolute path of the failing command:which php # Expected output: /usr/bin/php (or /usr/local/bin/php, /opt/php/bin/php, etc.) which node # Expected output: /usr/bin/node (or ~/.nvm/versions/node/vX.Y.Z/bin/node, etc.) which composer # Expected output: /usr/local/bin/composer - Update Your Crontab Entry:
Replace the command name with its absolute path:
# Original (failing): # * * * * * php /var/www/html/script.php # Corrected with absolute path: * * * * * /usr/bin/php /var/www/html/script.php >> /var/log/my_cron_job.log 2>&1If your command is within a user's home directory (e.g.,
.nvmfor Node.js), the absolute path will be/home/youruser/.nvm/versions/node/vX.Y.Z/bin/node.
4. Define PATH within the Crontab File
If using absolute paths for every command is cumbersome, you can define a custom PATH variable at the top of your crontab file. This PATH will apply to all subsequent cron entries in that crontab.
- Edit Crontab:
Open your
crontabfor editing:crontab -e - Add
PATHDefinition: At the very top of the file (before any cron job entries), add aPATHline. You should include cron's default paths and any additional directories required.MAILTO="[email protected]" PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/home/youruser/.nvm/versions/node/v16.14.0/bin:/usr/local/php8.2/bin # Your cron job entries below: * * * * * php /var/www/html/script.php >> /var/log/my_cron_job.log 2>&1 0 1 * * * node /home/youruser/app/worker.js >> /var/log/my_node_worker.log 2>&1- The
PATHline must start withPATH=and contain colon-separated directory paths. - Do not use
exporton this line withincrontab. ThePATHvariable is implicitly exported to all subsequent cron jobs. - Ensure you include the standard system paths (
/usr/bin:/bin, etc.) in addition to your custom paths, or you might break other commands. You can get a good base by runningecho $PATHin your interactive shell and adding necessary custom paths.
- The
5. Use a Wrapper Script for Complex Jobs
For jobs involving multiple commands, specific environment variables, or complex logic, a wrapper shell script is the most robust and maintainable solution.
Create the Wrapper Script: Create a new shell script (e.g.,
run_my_app.sh) in a suitable location (e.g.,~/binor/opt/scripts).#!/bin/bash # --- Set Custom Environment Variables (including PATH) --- export PATH="/home/youruser/.nvm/versions/node/v16.14.0/bin:/usr/local/php8.2/bin:$PATH" export NODE_ENV="production" # Add any other required environment variables # --- Navigate to the Application Directory (if needed) --- cd /var/www/html/my_project || { echo "Failed to change directory" >&2; exit 1; } # --- Execute Your Commands --- # Example 1: Laravel scheduler /usr/bin/php artisan schedule:run >> /var/log/laravel_cron.log 2>&1 # Example 2: Node.js application node index.js >> /var/log/node_app_cron.log 2>&1 # Example 3: WordPress WP-CLI wp cron event run --due-now >> /var/log/wp_cron.log 2>&1- The
#!/bin/bashshebang ensures the script runs with Bash, allowing more advanced shell features. - Use
exportfor environment variables within the script, as you would in a regular shell script. - You can prepend your custom paths to the existing
PATHusingexport PATH="/your/custom/path:$PATH". - Always redirect output to a log file within the script for easier debugging.
- The
Make the Script Executable:
chmod +x /path/to/your/run_my_app.shUpdate Crontab: Your crontab entry now simply calls the wrapper script:
# Crontab entry * * * * * /path/to/your/run_my_app.shThis method encapsulates all environment setup and command execution logic, making your crontab cleaner and the job more robust.
6. Debugging PATH Syntax Errors (If You Tried to Set It Incorrectly)
If you've attempted to set PATH directly in a cron command and observed new errors, review the syntax.
Incorrect (Often Leads to Errors):
# This might work for simple commands, but is prone to errors, especially with expansions * * * * * export PATH=/my/custom/path:$PATH; /usr/bin/mycommandThe
exportkeyword is generally redundant and can sometimes confuseshwhen used in this inline context. Also,$PATHexpansion within a single command line entry can be unreliable or require careful escaping depending on the shell cron uses.Better (Inline, but still less ideal than a wrapper or global PATH):
# Prepend PATH for a single command, without 'export' * * * * * PATH=/my/custom/path:/usr/bin:/bin /usr/bin/mycommandThis sets
PATHfor the duration of that single command.For consistency and maintainability, prefer defining
PATHat the top of yourcrontab(Step 4) or using a wrapper script (Step 5) over complex inlinePATHmodifications in individual cron job lines.
7. Test and Validate
After making changes:
- Wait for the next scheduled run or, for quick testing of a specific command, adjust the cron schedule to run in the next minute.
- Check your log files (
/var/log/syslog,/var/log/my_cron_job.log, etc.) or your email (MAILTO) for success messages or any new errors. - Verify the desired outcome of the cron job (e.g., check database updates, file changes, service restarts).
By following these steps, you should be able to precisely diagnose and resolve PATH related issues preventing your cron jobs from running correctly on Ubuntu 20.04 LTS.