Back to sensacat

Home  /  Troubleshooting

· SensaCat Team

Cron Job Failed Silently and Nobody Noticed

The job ran, exited zero, and did nothing. Here is where the error went and why the exit code lied.

Start by establishing which of two things happened: the job did not run, or it ran and failed without saying so. They have completely different causes and the check takes one command.

If there is a CMD line at the expected time, cron executed your command and the problem is inside it. If there is nothing, the schedule itself is broken, which is covered in why did my scheduled job stop running.

Where the error message went

Cron captures stdout and stderr and mails them to the job's owner. On almost every modern server there is no mail transfer agent installed, so the message is generated, delivery fails, and the text describing your failure ceases to exist.

This is the single biggest reason cron failures are invisible. The job told you exactly what went wrong and the machine threw the note away.

Check whether output was being mailed and silently dropped by looking for a MAILTO line at the top of the crontab. An empty MAILTO="" means output is discarded deliberately, which someone may have added years ago to stop noise.

Why the exit code said success

Several common shapes of script report success while failing. Each is worth checking directly.

Pattern Why it exits 0 Fix
Plain shell script Only the last command's status is returned set -euo pipefail at the top
Command in a pipeline Only the final command's status counts Check ${PIPESTATUS[@]}, or set -o pipefail
try/except with a bare pass The exception was caught and discarded Log and re-raise, or report explicitly
Backgrounded with & The shell returns before the work finishes Remove the &, or wait and check
Exit code ignored after a redirect Redirection does not change status Test $? immediately

The -f flag on curl matters as much as pipefail. Without it, curl returns 0 for a 404 or a 500, writes the error page to your file, and the pipeline processes an HTML error document as if it were data.

The job that ran perfectly and did nothing

This is the hardest version, because every signal is genuinely correct. The script ran, made no errors, and exited cleanly. It simply processed zero records, because an upstream API returned an empty array or a query matched nothing.

No amount of exit-code discipline catches this. The only thing that does is having the job assert something about its own output.

Pick a threshold from your own history rather than zero where you can. An import that normally brings in 800 to 3,000 rows and brought in four is broken, and a zero check will not catch it.

Finding out faster next time

Log the start and end of every job with a timestamp, keep the log where a human will find it, and make the job report a failure rather than relying on someone spotting an absence.

A heartbeat monitor closes the remaining gap, because it alerts on the run that never happened at all. That is the category SensaCat covers. The concept is explained in heartbeat monitoring.