← Blog  ·  October 2026

GitHub Actions Scheduled Workflow Not Running: Causes and Fixes

The scheduled run silently stopped. No error, no notification, no indication anything changed.

GitHub Actions scheduled workflows (on: schedule:) are supposed to run reliably on a cron expression. In practice, they stop running more often than developers expect — and they do it silently. Your workflow simply doesn't appear in the Actions tab. No failure notification. No email. Just a gap in the run history.

This is one of the more frustrating problems in developer tooling because the failure mode is invisible. Here are the five most common causes and how to handle each one.


1. The repository inactivity freeze (the #1 cause)

This is the cause that surprises most people. GitHub automatically disables scheduled workflows on repositories that have had no activity for 60 days. "Activity" means pushes, pull requests, or other repository events — not workflow runs themselves. If you have a scheduled job that runs in an otherwise-idle repo, GitHub will disable it after 60 days and send you one email notification. If you miss that email, the workflow just stops.

⚠️ Common scenario A monitoring script, nightly report, or cleanup job runs weekly in a repo where the code itself doesn't change often. After two months of inactivity in the repo, GitHub disables the workflow. The cleanup stops running. You don't find out until something downstream breaks.

How to check: Go to your repo → Actions → find the workflow → look for a yellow banner at the top saying the workflow was disabled.

How to fix: Click "Enable workflow" in the Actions tab. To prevent recurrence, add a workflow_dispatch: trigger as a second trigger — this doesn't require you to actually use it, but the existence of a manual trigger keeps the workflow considered "active".

on:
  schedule:
    - cron: '0 9 * * 1'   # Every Monday at 9am UTC
  workflow_dispatch:        # Add this — prevents inactivity disable

2. Wrong cron expression syntax or timezone assumption

GitHub Actions cron syntax follows standard five-field cron format, but there are two important constraints:

A subtle bug: writing 0 9 * * 1-5 to run on weekdays at 9am UTC works as expected, but 0 9 * * MON-FRI (using day names) may not be supported depending on your runner version. Stick to numbers.

🔍 Validate your cron expression

Before deploying a scheduled workflow, verify the expression parses correctly and runs at the times you expect.

Parse cron expression →

3. Scheduled runs queue and drop under high load

GitHub's documentation acknowledges that scheduled workflows may be delayed or not run at all during periods of high load on GitHub's infrastructure. The scheduler is best-effort, not guaranteed. In practice this is rare — but for workflows where timing matters (nightly jobs with downstream dependencies, billing cycles, time-sensitive cleanup), a 15–60 minute delay or an occasional complete miss is within the expected behavior.

The documented guidance is not to use GitHub Actions scheduled workflows for time-critical operations. If a job must run within a narrow window, use a dedicated scheduler (a cron daemon, AWS EventBridge, a monitoring service) that guarantees delivery.


4. The workflow file is on the wrong branch

Scheduled workflows are only active on the default branch of your repository. If you add or modify a schedule: trigger in a feature branch, it won't run — even after a push. The schedule only takes effect once the workflow file is merged to the default branch (usually main or master).

A common mistake: you add a scheduled workflow on a feature/monitoring branch for testing, it doesn't run, you assume the cron expression is wrong and start debugging the syntax, when the real problem is that the file hasn't been merged yet.

How to check: Confirm the workflow file exists in .github/workflows/ on your default branch, not just on a feature branch.


5. The job ran but the steps failed silently

Sometimes the workflow does run, but a step exits with a non-zero code that doesn't cause the overall job to fail because the step is configured with continue-on-error: true, or the failure is swallowed inside a shell script with set -e but the error-producing command is in a subshell or pipeline where exit codes are lost.

This is different from the workflow not running — the run appears in the history as "Success" — but no actual work was done. The database wasn't updated. The email wasn't sent. The cleanup didn't happen.

How to check: Look at the workflow run log for each step. Check for outputs like "0 rows affected" or empty results that indicate the job ran but did nothing. If you're using shell scripts, add set -euo pipefail at the top of every script to surface errors that would otherwise be silently ignored.

steps:
  - name: Run nightly sync
    run: |
      set -euo pipefail
      node scripts/sync.js

Summary: checklist when a scheduled workflow stops running

CheckWhere to lookFix
Repository inactivity freeze Actions tab → yellow banner Re-enable + add workflow_dispatch:
Wrong cron expression Validate expression in a cron parser Fix expression; remember UTC only
GitHub infrastructure delay Check run history for missing slots Use external scheduler for critical jobs
Workflow on wrong branch Check .github/workflows/ on default branch Merge workflow file to main
Job runs but steps fail silently Workflow run logs, step-by-step output Add set -euo pipefail to shell steps

The deeper problem: scheduled jobs have no heartbeat

All five causes above share a common root: there is no heartbeat for scheduled jobs. When a cron job works, you never hear from it — which means when it stops working, you also never hear from it. The default state is silence in both cases.

The inversion is monitoring from the outside: instead of waiting for a failure notification (which may never come), you configure an external service to expect a check-in at every scheduled interval. If the check-in doesn't arrive within the expected window, you get alerted. This is the dead man's switch pattern — a signal that must be renewed, rather than a signal sent only on failure.

For GitHub Actions specifically, the pattern is straightforward:

steps:
  - name: Run nightly sync
    run: node scripts/sync.js

  - name: Ping monitor
    if: success()
    run: curl -s https://your-monitor-url/ping/your-job-id

If step 1 fails, step 2 never runs. Your monitoring service sees a missed check-in and alerts you within minutes of the missed window — rather than days later when a user notices something is wrong.

📟 Get alerted when your scheduled workflows miss their window

CronWatch monitors your scheduled jobs across GitHub Actions, Heroku Scheduler, crontab, and AWS EventBridge. When a job misses its window — for any reason — you get an alert within minutes.

Join CronWatch waitlist → Validate cron expression →

Related reading