Skip to content
Get started

GitHub Actions cron not running: how to tell if it actually ran

If a GitHub Actions scheduled workflow stops running, the usual cause is that GitHub disables schedules after 60 days of no repository activity, the workflow file isn't on the default branch, or the run was delayed or dropped during peak load. GitHub does not notify you when a scheduled run never fires, so the reliable way to know a job ran is to have the job itself report success to an external monitor and alert you when that report doesn't arrive.

Why did my GitHub Actions cron stop running?

GitHub Actions scheduled workflows fail to run for a few well-documented reasons. Work through these in order:

  • Repository inactivity: GitHub automatically disables scheduled workflows in a public repository after 60 days with no commits. A bot's own commits may not count as activity, so a repo whose only changes come from the scheduled job can quietly get its schedule turned off.
  • The workflow isn't on the default branch: schedule triggers only run from the workflow file on the repository's default branch (usually main). A schedule added on a feature branch never fires.
  • Delayed or dropped runs under load: scheduled events are queued on a best-effort basis and can be delayed during periods of high load, especially near the top of the hour. GitHub does not guarantee a scheduled run starts at the exact minute, and heavily contended minutes can be skipped.
  • A syntax or quota problem: an invalid cron expression, or a repository that has hit its Actions usage limits, stops runs without an obvious error on the schedule itself.

How do I know if my GitHub Actions cron ran?

The Actions tab shows runs that happened, but it cannot show you a run that never started — and a missing run is exactly the failure you care about. The dependable approach is a dead man's switch: the job pings an external URL when it finishes, and something else alerts you when that ping doesn't arrive on schedule.

Add a final step that sends an HTTP request on success. Point it at a monitoring endpoint that expects a ping on your schedule:

.github/workflows/nightly.yml
name: Nightly job
on:
  schedule:
    - cron: "0 3 * * *"   # 03:00 UTC daily
  workflow_dispatch:        # lets you trigger a manual test run

jobs:
  nightly:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run the job
        run: ./scripts/nightly.sh

      # Ping AFTER the job succeeds. If the job fails, this step is skipped,
      # no ping arrives, and the monitor alerts you that the run missed.
      - name: Report success
        if: success()
        run: curl -fsS -m 10 --retry 3 "https://ping.cronshield.com/<your-check-id>"
The CronShield heartbeat receiver ships in an upcoming release. The URL above is a placeholder for the check-specific endpoint you'll get when you create a monitor — the pattern is what matters today.

How do I get alerted when a run is missed?

Set the monitor's expected period to match your cron (daily, hourly, or a specific window) plus a grace period for GitHub's scheduling delay. If no ping arrives inside that window, you get an email that the run missed. That closes the gap the Actions tab leaves open: you learn about a silently disabled schedule in minutes, not when someone notices stale data days later.

On the free tier that email tells you the run was missed. On the paid tiers, CronShield also reads the failing run's logs and puts the last log line plus a likely cause in the alert itself — so you triage from the notification instead of opening the Actions tab. That log-aware diagnosis is the paid tier's job; see how it works on the pricing page.

How do I stop GitHub from disabling my schedule?

Keep the repository active: merge a real change at least every couple of months, or ensure your scheduled workflow commits something back. A monitor helps here too — if GitHub disables the schedule, the missed-ping alert is your signal to re-enable it from the Actions tab, rather than discovering it weeks later.

Add a missed-run alert to this job

The free tier gives you a heartbeat endpoint and an email alert when an expected ping doesn't arrive. Paid tiers add the log-aware diagnosis — the last log line and a likely cause in the alert. The heartbeat receiver ships in an upcoming release; see the plans to learn what each tier adds.

Frequently asked questions

Does GitHub email me when a scheduled workflow fails to run?
No. GitHub emails you when a run fails, but not when a scheduled run never starts — for example after the schedule is auto-disabled for inactivity. That silent-miss case is why an external heartbeat monitor is worth adding.
Why does my cron run late in GitHub Actions?
Scheduled events run on a best-effort basis and can be delayed during high-load periods, especially near the top of the hour. Give your monitor a grace period, and schedule for an off-peak minute (for example 7 minutes past the hour) to reduce contention.
Can I test the schedule without waiting for the cron?
Yes. Add workflow_dispatch to the on: block so you can trigger a manual run from the Actions tab, confirm the ping arrives, then let the schedule take over.