Debugging and troubleshooting cron jobs

Usually when I have mysterious problems with a new crontab, it's that I'm not getting any results or output as expected, as if the command didn't run at all. Almost always, the newly added line to crontab was run. What did it do, what was the output, when did cron run? What should we check for?

  • Rarely, there is a problem in the time/data fields. The fields are:

    • minute
    • hour
    • day of month
    • month
    • day of week
    • then the command

    So make sure there are exactly 5 numbers or stars () before the command. Then make sure you didn't mix up day of month for day of week. Month will almost always be '', and days will usually be too. For testing, you can set minute and hour to '*' so that it can be tested every minute - so * * * * * /command/goes/here.

    You can also have commas (,) and slashes (/) in the number fields. Commas separate values and any of them will trigger the job. Slashes mean every X of that field it will run. So to run cron every 2 hours daily on the half hour or every 4 hours of every day:

    30 */2 * * * /run/me/every/2/hours

    0 */4 * * * /run/me/every/4/hours

  • The next common problem is that the environment which the cron job is running in is different from what you run from your shell. You'll have unset environment variables or different values. The main one is $PATH. So it's safe to just use full pathnames to all files, including the command. (There can still be a path problem if some scripts you are calling expect a certain path to be set) You can set variables in a crontab the same as in a shell script, e.g. PATH=/first/path:/second/path:/third/path.

  • Where does cron's output go? If any of your cron jobs prints output, it will automatically be mailed to you. It will try to send mail locally to your user which is probably not an email account you ever check. So this behavior is often not what you want and that's when you should redirect command line output to /dev/null, e.g. * * * * * /command/goes/here > /dev/null. Alternatively, you can set the email receive address as the MAILTO variable, e.g. on a line by itself at the top of your crontab:

    MAILTO="[email protected]"

    You need your server to be able to send mail for this to work, even if it can't receive mail. But if you aren't set up as a proper mail server, the chances of your message getting flagged as spam and not going into your own inbox are very high.

  • Instead of email, you can simply output a cron job to a file (e.g. a log file you have write access to) or even a dynamically named file using the date command.

  • If you still have problems with your cron job while it runs perfectly fine from bash, then there is probably something different in your environment variables. It could be something you're setting in your bash .profile or .bashrc. You can run env in your shell, and then run it via cron and save to a file (or email yourself) to compare.

    * * * * * /usr/bin/env > /tmp/cron_env

    Wait a minute and then run env | diff /tmp/cron_env -.

Now you should be able to try your cron line from the shell, then add it to your crontab, and see it running exactly as it ran manually.