DEV Community

dpm_bush
dpm_bush

Posted on

Debugging systemd Timers That Never Run

A systemd timer can be enabled and still not run when you expect. The timer may be waiting for its next scheduled time, its service may be failing, or the schedule may behave differently after a machine has been offline.

Here’s a practical way to trace a timer from its schedule to the command it starts.

Start with the timer’s actual state

List timers systemd currently knows about:

systemctl list-timers --all
Enter fullscreen mode Exit fullscreen mode

The output includes the last activation, the next activation, and the unit the timer activates. --all matters: without it, inactive timers are omitted.

For one timer, inspect its status and loaded configuration:

systemctl status backup.timer
systemctl cat backup.timer
Enter fullscreen mode Exit fullscreen mode

Replace backup.timer with your unit name. Check whether it is loaded, active, and enabled—and whether systemctl cat shows the file you meant to configure. A timer can be active for a different unit than the one you’re editing.

If you need help interpreting the fields in systemctl status, see this guide to reading systemctl status output.

Confirm which service the timer starts

A timer typically activates a service with the same base name. For example, backup.timer activates backup.service by default.

The timer can also specify a different unit explicitly:

[Timer]
OnCalendar=*-*-* 02:30:00
Unit=nightly-backup.service
Enter fullscreen mode Exit fullscreen mode

Inspect that service rather than assuming the timer’s name identifies it:

systemctl cat nightly-backup.service
systemctl status nightly-backup.service
Enter fullscreen mode Exit fullscreen mode

A timer can be working perfectly while the service exits with an error. Check the service’s recent logs:

journalctl -u nightly-backup.service -n 50 --no-pager
Enter fullscreen mode Exit fullscreen mode

For a broader look at filtering and following system logs, use this journalctl guide.

Check whether the schedule means what you think

OnCalendar= uses systemd’s calendar syntax. A daily run at 02:30 looks like this:

[Timer]
OnCalendar=*-*-* 02:30:00
Enter fullscreen mode Exit fullscreen mode

Validate the expression without waiting for the timer:

systemd-analyze calendar '*-*-* 02:30:00'
Enter fullscreen mode Exit fullscreen mode

This prints the next matching time. It’s a quick way to catch an expression that parses but doesn’t describe the schedule you intended.

A common surprise is the difference between calendar timers and monotonic timers. OnCalendar= refers to wall-clock time. OnBootSec= and OnUnitActiveSec= are relative to boot or a unit’s activation, respectively. They solve different scheduling problems; choosing the wrong one can make a timer appear to run too early, too late, or only after a reboot.

For example, a service that should run ten minutes after boot can use:

[Timer]
OnBootSec=10min
Enter fullscreen mode Exit fullscreen mode

A service that should run an hour after its previous activation can use:

[Timer]
OnUnitActiveSec=1h
Enter fullscreen mode Exit fullscreen mode

Decide what should happen after downtime

If a machine is powered off at the scheduled time, a regular calendar timer doesn’t necessarily run the missed job when the machine comes back.

For work that should catch up after downtime, add Persistent=true:

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
Enter fullscreen mode Exit fullscreen mode

For a calendar timer, systemd records when it last triggered. If one or more scheduled times passed while it was inactive, persistence causes it to trigger after activation. It does not replay every missed occurrence; don’t treat it as a durable job queue.

This is useful for jobs such as a daily cleanup that should happen eventually. It may be inappropriate when every individual run matters or when running several jobs back-to-back would be harmful.

Apply changes and enable the right unit

After editing a unit file, ask systemd to reload unit definitions, then enable and start the timer:

sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
Enter fullscreen mode Exit fullscreen mode

daemon-reload makes systemd reread unit files; it does not run the service or restart the timer’s target. This explanation of daemon-reload covers what it does and when it’s needed.

If you only changed the timer schedule, restarting the timer ensures the updated schedule is loaded:

sudo systemctl restart backup.timer
Enter fullscreen mode Exit fullscreen mode

Then verify the next activation:

systemctl list-timers --all
Enter fullscreen mode Exit fullscreen mode

Test the service independently

Don’t wait for the next scheduled time to find out whether the command works. Start the service directly:

sudo systemctl start backup.service
Enter fullscreen mode Exit fullscreen mode

Then check its result and logs:

systemctl status backup.service
journalctl -u backup.service -n 50 --no-pager
Enter fullscreen mode Exit fullscreen mode

If manual activation fails, investigate the service before changing the timer. Timer-started services don’t necessarily get the same environment as your interactive shell: a command available through your shell’s PATH, for instance, may need an absolute path in the unit’s ExecStart=.

A short diagnostic sequence

When a timer seems stuck, work through these checks in order:

  1. systemctl list-timers --all — is it scheduled, and what unit does it activate?
  2. systemctl cat name.timer — does the loaded schedule match your file?
  3. systemd-analyze calendar 'EXPRESSION' — does the next run time make sense?
  4. systemctl status target.service — did the service start and finish successfully?
  5. journalctl -u target.service — what did the service report?
  6. If downtime matters, decide whether Persistent=true fits the job.

This separates scheduling problems from execution problems. A timer’s next activation tells you when systemd plans to start work; the service status and logs tell you whether that work succeeded.

I'm building SSHFlow — an SSH client that organizes terminals, SFTP, code editing, and server tools into workspaces.

Top comments (0)