Common causes
- Commands like php, node or wp are not on cron's short PATH (/usr/bin:/bin)
- Relative paths that only work from your home or project directory
- The script is not executable or lacks a #! shebang line
- An unescaped % in the command, which cron converts to a newline
- Wrong schedule syntax, a missing trailing newline, or the job was added to the wrong user's crontab
- The server time zone differs from what you expect, so the job runs at another hour
How to fix it
- Confirm cron fired the job. Check grep CRON /var/log/syslog (Debian/Ubuntu), /var/log/cron (RHEL) or journalctl -u cron (cron.service on Debian/Ubuntu, crond.service on RHEL). A CMD line at the expected time means cron ran it and the command itself failed.
- Capture the output. Append >> /var/log/myjob.log 2>&1 to the crontab line. The "No MTA installed" message means output was being discarded, so this log will show the real error.
- Use absolute paths. Find binaries with which php and write them in full, for example /usr/bin/php /var/www/app/artisan schedule:run. cd into the project directory first if the script uses relative paths.
- Make scripts executable. Run chmod +x /home/user/backup.sh and make sure the first line is a shebang such as #!/usr/bin/env bash or #!/bin/bash.
- Escape percent signs. Write date +\%F instead of date +%F inside crontab, or move the command into a script file.
- Check schedule and user. View the active crontab with crontab -l (or sudo crontab -u www-data -l). Confirm the server time zone with timedatectl and use CRON_TZ= where supported.
crontab -e
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
# Laravel scheduler every minute, with output logged
* * * * * cd /var/www/app && /usr/bin/php artisan schedule:run >> /var/log/app-cron.log 2>&1
# Nightly backup at 02:30, escaping %
30 2 * * * /home/user/backup.sh > /home/user/backup-$(date +\%F).log 2>&1 How to stop it happening again
- Always log cron output to a file or monitoring service
- Use absolute paths and set PATH at the top of the crontab
- Test the exact command with env -i /bin/sh -c '...' to mimic cron's environment
- Run jobs as the same user that owns the files they touch