Linux & OS Advanced

CentOS Stream / Rocky Linux Cron Job ‘command not found’ due to PATH Variable Syntax Error

Fix 'command not found' errors in Linux cron jobs caused by incorrect PATH variables on CentOS Stream and Rocky Linux. Learn advanced troubleshooting steps.

👨‍💻
Senior Systems Architect • Verified in Staging Labs

Fix 'command not found' errors in Linux cron jobs caused by incorrect PATH variables on CentOS Stream and Rocky Linux. Learn advanced troubleshooting steps.

When managing servers, it's common to set up cron jobs for automated tasks like backups, script execution, or system maintenance. A frustratingly common issue arises when a script or command that runs perfectly from your shell fails silently or with cryptic "command not found" errors when executed via cron. This almost invariably points to a mismatch in the environment variables, specifically the PATH variable, between your interactive shell and the minimal environment cron provides. This guide will walk you through diagnosing and resolving these PATH variable-related issues on CentOS Stream and Rocky Linux.

Symptom & Error Signature

You'll typically notice one of the following symptoms:

  • No output or unexpected behavior: Your automated task simply doesn't run, or produces no expected results.
  • Email notifications: If your MAILTO variable is set in the crontab, you'll receive emails containing error messages.
  • Log file entries: Your custom script's log file (if configured) or the system's cron logs (/var/log/cron or journalctl) will contain errors.

Here's what you might see in your email or log files:

Subject: Cron <user@hostname> /path/to/your/script.sh

/path/to/your/script.sh: line 5: php: command not found

Or a more generic cron daemon message (often in /var/log/cron or journalctl -u cronie):

Jul 30 10:00:01 hostname CROND[12345]: (user) CMD (/path/to/your/script.sh)
Jul 30 10:00:01 hostname CROND[12344]: (user) RELOAD (cron/user)
Jul 30 10:00:01 hostname CROND[12345]: (user) ERROR (grandchild #12346 failed with exit status 127)

The exit status 127 explicitly means "command not found," which is the quintessential indicator of a PATH variable issue.

Root Cause Analysis

The core of this problem lies in how cron jobs execute. Unlike an interactive login shell (like when you SSH into your server), which loads various profile scripts (.bashrc, .bash_profile, /etc/profile, etc.) that set up a rich environment, cron jobs run in a minimal, non-interactive shell environment.

This minimal environment typically has a highly restricted PATH variable. On CentOS Stream / Rocky Linux, cronie (the cron daemon) usually provides a default PATH like /usr/bin:/bin or similar. If your script relies on executables located outside these default directories (e.g., /usr/local/bin, /opt/rh/php74/root/usr/bin, /sbin, or even local user bins), the shell cron uses won't find them, leading to the "command not found" error.

Consider these key differences:

  1. Limited PATH: Your interactive shell's PATH might include /usr/local/bin, /home/user/.local/bin, /opt/php/bin, etc., but cron's PATH rarely does by default.
  2. No profile sourcing: Cron does not execute .bashrc, .profile, or other user-specific shell initialization files. Therefore, any environment variables or aliases defined there are not available to cron jobs.
  3. Default Shell: Cron jobs typically use /bin/sh by default, which is often a symlink to bash but behaves more like a POSIX shell, potentially impacting script syntax if not explicitly using #!/bin/bash.

The "syntax error" in the problem description often refers to the consequence of the PATH not being correctly set, where the shell implicitly tries to execute a command that isn't found, leading to a shell error rather than a direct PATH error message.

Step-by-Step Resolution

Follow these steps to diagnose and resolve your cron job PATH variable issues.

1. Verify the Cron Job Execution (Logging is Key)

The first step is to ensure your cron job is actually running and to capture any output, including errors.

Add redirection for stdout and stderr to a temporary log file within your crontab entry:

* * * * * /path/to/your/script.sh >> /tmp/cron_debug.log 2>&1
  • >> /tmp/cron_debug.log: Appends standard output to the specified log file.
  • 2>&1: Redirects standard error (file descriptor 2) to the same location as standard output (file descriptor 1).

After the job has had a chance to run, examine the /tmp/cron_debug.log file:

cat /tmp/cron_debug.log

If you see command not found errors here, you're on the right track.

If you have MAILTO="[email protected]" defined at the top of your crontab, cron will email all output (stdout and stderr) to that address. This is often the quickest way to get error feedback.

2. Inspect the Cron Environment's PATH

To understand what PATH cron is actually using, create a temporary cron job to log all environment variables:

  1. Open your user crontab for editing:
    crontab -e
    
  2. Add the following entry (adjust interval as needed, e.g., * * * * * for every minute):
    * * * * * env > /tmp/cron_env.log 2>&1
    
  3. Wait for the job to execute, then inspect the generated log file:
    cat /tmp/cron_env.log | grep PATH=
    
    This will show you the exact PATH variable cron is using. Compare this to your interactive shell's PATH:
    echo $PATH
    
    You'll almost certainly find a difference.

3. Use Absolute Paths for Commands (Recommended)

The most robust and highly recommended solution is to use absolute paths for all executables within your script or directly in the crontab entry. This eliminates reliance on the PATH variable altogether.

  1. Find the absolute path: Use the which command in your interactive shell to find the full path of the command that's failing.

    which php
    which composer
    which python3
    

    Example output:

    /usr/bin/php
    /usr/local/bin/composer
    /usr/bin/python3
    

    In some hosting environments (like cPanel with EA-PHP), PHP binaries might be in paths like /opt/cpanel/ea-phpXX/root/usr/bin/php. Docker containers might have custom paths. Always use which in the environment where the command works.

  2. Update your script or crontab:

    • In your script (.sh, .py, etc.): Replace relative command names with their absolute paths.
      #!/bin/bash
      # Original (fails in cron):
      # php /var/www/html/myscript.php
      
      # Corrected (uses absolute path):
      /usr/bin/php /var/www/html/myscript.php
      
    • Directly in crontab -e:
      # Original:
      # * * * * * php /var/www/html/myscript.php
      
      # Corrected:
      * * * * * /usr/bin/php /var/www/html/myscript.php
      

Using absolute paths is the most reliable method as it makes your cron jobs independent of the PATH environment variable.

4. Explicitly Set PATH in the Crontab

If using absolute paths for every command is cumbersome, you can define a PATH variable directly at the top of your crontab file. This PATH will apply to all subsequent cron entries in that crontab.

  1. Open your crontab for editing:
    crontab -e
    
  2. Add a PATH definition on a new line at the very top of the file, listing all necessary directories, separated by colons. Include the directories you found from echo $PATH in your interactive shell.
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/cpanel/ea-php81/root/usr/bin
    MAILTO="[email protected]" # Optional, but highly recommended for error notifications
    
    # Example cron job using the new PATH
    * * * * * php /var/www/html/myscript.php
    * 0 * * * /usr/local/bin/composer update --no-dev -d /var/www/html/your_project
    

    The order of directories in PATH matters. The system searches for executables in the order they appear.

5. Source User Profile (If Necessary and Cautiously)

In rare cases, if your script relies on complex environment variables or functions defined exclusively in your user's shell profile (.bashrc, .bash_profile), you might need to source these files.

* * * * * . ~/.bash_profile && /path/to/your/script.sh
# OR
* * * * * source ~/.bashrc && /path/to/your/script.sh

Sourcing profile files can introduce a large number of variables, aliases, and functions that might not be necessary or could even interfere with your cron job. This approach is generally less stable and harder to debug than explicitly setting PATH or using absolute paths. Use with caution and only if other methods fail.

6. Test the Script in a Non-Interactive Shell

Before setting up the cron job, test your script in a non-interactive shell environment to simulate how cron will run it. This helps catch PATH issues locally.

# Test with a minimal PATH
env -i PATH=/usr/bin:/bin /path/to/your/script.sh

# Test with a custom PATH (simulating your crontab PATH)
env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin /path/to/your/script.sh

# Test with the default shell
bash -c "/path/to/your/script.sh"
sh -c "/path/to/your/script.sh"

The env -i command starts a new environment with no inherited variables, mimicking cron's clean slate.

7. Check Script Permissions and Shebang

Ensure your script has executable permissions and a correct shebang line. While not directly a PATH issue, incorrect permissions or shebangs can manifest as "command not found" if the kernel doesn't know how to execute the file.

  1. Executable permissions:
    chmod +x /path/to/your/script.sh
    
  2. Shebang line: The very first line of your script should specify the interpreter.
    #!/bin/bash
    
    or for Python:
    #!/usr/bin/env python3
    
    or for PHP CLI scripts (if not invoked directly by php):
    #!/usr/bin/env php
    
    #!/usr/bin/env is often preferred as it uses the PATH to find the interpreter, making it more portable if the interpreter's absolute path changes. However, if your cron PATH is broken, even env might not find it.

8. Review Cron Daemon Logs (/var/log/cron or journalctl)

For system-wide cron issues or if you suspect the cron daemon itself, check the system logs.

On CentOS Stream / Rocky Linux with Systemd:

sudo journalctl -u cronie.service -f

This command displays real-time logs for the cronie service. Look for CROND messages indicating execution failures or unusual activity.

Alternatively, you can examine the traditional log file:

sudo grep CRON /var/log/cron

By systematically applying these troubleshooting steps, you can accurately pinpoint and resolve PATH variable syntax errors, ensuring your Linux cron jobs run reliably as intended.

👨‍💻

Johnathon Wheeler

Senior Systems Architect & DevOps Engineer • Austin, TX

Connect on LinkedIn →

Johnathon has over 16 years of hands-on experience designing, debugging, and scaling Linux web hosting stacks, container clusters, and high-availability database architectures. Every guide on ButItWorkedLocal is independently tested against Debian 12, Ubuntu 24.04/22.04 LTS, Rocky Linux, and Docker environments to guarantee reproducibility in production.

🛡️

Our Production Verification Guarantee

Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.