Synthetic Industry

Troubleshooting guide · updated 2026-10-11

A cron job stopped or does nothing: check its environment, mail, percent signs and overlap

Why a command that works by hand fails from cron, how the scheduler treats environment, output, percent signs and day fields, and how to stop runs overlapping.

Works by hand, fails from the schedule

The most common cron story is a command that runs perfectly in a terminal and does nothing from the schedule. The reason is that your terminal has your whole environment: your PATH, your profile, your current directory, your credentials helper. Cron has far less. The crontab(5) page for Debian's cron says it sets SHELL to the basic Bourne shell and takes LOGNAME and HOME from the account's entry, and describes environment settings only as those plus lines you put in the crontab itself. It does not run your login profile. A program found by name in your shell may not be found in cron's smaller world.

The first reproduction step is therefore to run the command with a cleaned environment, as the same user, from the same working directory cron uses, and see what breaks.

  • Use absolute paths for programs and files in the schedule line or a wrapper.
  • Set the variables the job needs explicitly, with secrets kept out of the crontab file and the repository.

Output and mail: where the error went

When a cron command prints anything, the scheduler mails that output to the crontab's owner unless MAILTO is set to someone else. If MAILTO is set but empty, no mail is sent at all. On many servers there is no working mail transport, or the mailbox is local and unread, so the error message was produced and discarded. This is why a job can fail daily for months with no sign.

Redirect the job's own output to a log file with a timestamp, and make failures loud: have the wrapper exit non-zero on error and report it somewhere a person looks. A log nobody reads is better than none only if a monitor tells you when it stops being written.

  • Check the MAILTO line and whether the host can deliver mail.
  • Keep a rotated log for each job.

Percent signs and day fields

Two quirks catch careful people. In the command field of a crontab entry, an unescaped percent sign is turned into a newline, and everything after the first one is fed to the command as standard input. A date command with a format string such as %Y-%m-%d silently breaks unless each percent sign is escaped with a backslash, or the logic is moved into a script. The second quirk: if both the day-of-month and the day-of-week fields are restricted, the job runs when either matches, not both. A line meant to run on the first Monday of the month instead runs on every first of the month and every Monday.

Neither error produces a message. Both are visible by reading the schedule line carefully, which is why the first check in the paid job is a line-by-line read of the entry.

  • Escape percent signs or move the command into a script.
  • Do not combine day-of-month and day-of-week unless you want the either-or rule.

Overlap and missed runs

A job that sometimes takes longer than its interval can start a second copy while the first is still working, doubling the load and sometimes corrupting shared files. Wrap the command in a lock. The flock utility takes a lock around a command, and with its non-blocking option it gives up immediately, exit status 1, when another copy holds the lock, so the second run stops quietly and says so in the log. The lock is released when the process ends, even on failure.

Finally, cron only runs jobs while the machine is up. If the host was off at the scheduled minute, that run simply does not happen. A heartbeat monitor that expects a signal on each run will notice; the companion guide explains how. The cron outcome fixes one job on a test host, adds the lock and the signals, and proves a failed and a skipped run both reach a named person.

  • Log when a run is refused because the lock is held.
  • Decide whether a missed run should be made up or skipped.

Sources and limits

  • Debian crontab(5) manual page (cron 3.0pl1) Checked 2026-10-11.
    • cron sets SHELL to the basic Bourne shell and takes LOGNAME and HOME from the crontab owner's password entry.
    • Output is mailed to the crontab owner unless MAILTO says otherwise, and an empty MAILTO sends no mail.
    • An unescaped percent sign in the command field becomes a newline and the text after the first one is passed as standard input.
    • If both day-of-month and day-of-week are restricted, a match on either runs the command.
  • flock(1) manual page Checked 2026-10-11.
    • flock takes a lock around a command, and with the non-blocking option gives up at once with an exit status of 1 when the lock is held.