If your cron job is not running, check whether the scheduler launched it. If it did, follow the command through to its output. Rewriting the schedule will not fix a missing dependency; adding a success notification will not catch a machine that never starts the job.
This guide is for Linux cron jobs. Service names, log locations, and cron extensions vary by distribution. Use your installed manual pages when they differ from the examples.
Find where the cron job stopped
| Evidence | Investigate next |
|---|---|
| No launch record | Installed schedule, account, scheduler service, host availability |
| Launch record but no application output | Command path, interpreter, permissions, log destination |
| Application starts and fails | Configuration, dependencies, credentials, network access |
| Exit status is zero but output is missing | Application success criteria and swallowed errors |
| Runs are intermittent | Overlap, resource pressure, locks, timing assumptions |
Keep a record of the expected run time, observed start, exit status, and output artifact. Those details help you reproduce the failure instead of changing settings at random.
Check the installed schedule and account
Read the relevant user's schedule with crontab -l. Confirm that it is the account intended to own the job. For system schedules, inspect the appropriate system configuration instead; its format can differ from a user crontab.
Cronie user entries have five timing fields followed by the command. System entries include a user field. The shell defaults to /bin/sh; unescaped percent characters inside a cron command have special meaning. Put complex shell logic in a script rather than squeezing it into the schedule. These details are documented in the Cronie crontab manual.
Check the host clock and the scheduler's configured timezone. Do not assume a schedule uses the timezone displayed on your laptop. Check your cron implementation's daylight-saving behavior if the missing run coincides with a clock change.
Establish whether the scheduler launched the job
Read the scheduler service status and logs on the machine that should run it. On systems using systemd, administrators commonly inspect the relevant unit with systemctl status and journalctl -u; identify the actual unit name on your distribution first.
A scheduler launch record is only evidence of an attempted start. Follow it into the application log. Look for interpreter errors, denied access, and a log path that the scheduled account cannot write.
Do not repeatedly run a production cleanup, billing task, or migration while diagnosing it. Reproduce the failure with a read-only check or a disposable fixture where possible.
Make the job's environment explicit
A terminal session may have activated a virtual environment, loaded credentials, or changed directories. Make those requirements explicit in the scheduled command.
For example, a Python job can have a small wrapper that selects its own directory and interpreter. Replace these example paths with the paths to your application:
#!/bin/sh
set -eu
cd /opt/report-job
exec /opt/report-job/.venv/bin/python /opt/report-job/report.pyRun the wrapper as the scheduled account in a controlled environment before adding it to cron. Supply required secrets through your existing protected configuration mechanism. Avoid printing the full environment into a troubleshooting log.
Check file access along the entire path, including parent directories. Confirm that the interpreter and dependencies exist on the machine running the schedule, not just on your workstation.
Separate a failed command from incorrect output
An exit status of zero reflects the application's definition of success. A program might catch an exception and return normally, or produce an empty file without treating that as an error.
Define what the consumer needs. For a daily report, that could mean a new file for the expected reporting date, valid structure, and the expected source coverage. For a backup, a successful upload is one check; a successful restore is a separate test.
Make those validations part of the job. Only report success after they pass. Avoid checking only whether an old output file exists, because yesterday's artifact can hide today's failure.
Detect the next missed run independently
A failure message sent by the job depends on that job executing. A heartbeat monitor instead holds an expectation outside the job and detects when the expected signal is absent.
Use distinct signals for start, successful completion, and explicit failure when your monitor supports them. Configure a grace period for normal scheduling variation and a runtime limit for work that starts but does not finish. A generic “still alive” ping should not substitute for validated completion.
ActionBox Watches support this pattern. Confirm Watch availability for your account using the Watch documentation; disabled Watch support requires contacting ActionBox, not changing a client setting. The cron monitoring guide explains the integration and recovery behavior.
Validate the monitoring, too
Before relying on the setup, use a disposable job to exercise four cases: successful completion, explicit failure, a deliberately omitted run, and a run that exceeds its expected duration. Record the state changes for each case. Receiving one notification does not tell you whether the other cases work.
Restore normal scheduling afterward. Keep the heartbeat capability out of screenshots and logs. Notification delivery and an operator acknowledging an incident are separate events.
If the job runs but needs permission before a risky operation, use a cron approval workflow. For missing or failed execution, begin with monitoring and a clear runbook.
Create a free Source to begin setup, then confirm Watch availability before relying on monitoring.
