DEV Community

zhihu wu
zhihu wu

Posted on

5 Cron Gotchas That Silently Break Your Jobs (and How to Fix Them)

Cron looks simple: five fields and a command. But some of its oldest quirks are exactly where jobs fail silently — usually at 3 AM when nobody is watching. Here are five gotchas I've hit (or watched teammates hit), with the fixes.

1. Day-of-month and day-of-week are OR, not AND

30 2 1 * 1 does NOT mean "the first of the month AND Monday." Cron fires the job if EITHER field matches — so this runs at 2:30 AM on the 1st of every month AND at 2:30 AM every Monday. To target a true "first Monday," keep the schedule simple and add a guard inside the command that checks the day of month is within the first 7 days.

2. Cron runs in the server's timezone, not yours

0 0 * * * means midnight in whatever timezone the host is set to. Docker containers default to UTC, and cloud VMs are often UTC too — so your "daily midnight" job can silently run at 8 AM your time. Check with the date command in the same environment, and use CRON_TZ if your cron implementation supports it.

3. The percent sign means newline

In a crontab entry, % is translated to a newline. A command like date +%Y-%m-%d will break or behave oddly. Escape it as \% — or better, put the logic in a script file and keep the crontab line trivial.

4. Cron gives you a minimal environment

Cron does not source your shell profile. PATH is often just /usr/bin:/bin, so anything installed via nvm, pyenv, or a project virtualenv "works in my terminal" but fails only under cron. Fix: use absolute paths in the script and export PATH at the top of the script itself.

5. Overlaps and silence

If a job runs longer than its interval, cron happily starts a second instance — wrapped in flock to prevent it. And if stdout isn't redirected and no mail daemon exists, error output quietly disappears. Redirect to a log file and add an external health check so a dead job actually alerts you.

Gotchas like these are why I test a schedule before deploying it. When I need to decode an unfamiliar expression or build one from scratch, I use the free CodeToolbox Cron Generator — it validates each field and explains the schedule in plain language, and everything runs locally in your browser, so nothing gets uploaded.

Top comments (0)