GitHub Actions: scheduled workflow not triggering [2026 fix]
CRON syntax error or disabled workflow branch protection—add `permissions:` block and verify schedule format matches UTC only.
GitHub Actions: Scheduled Workflow Not Triggering at 2AM
TL;DR
Cause: CRON schedule uses local timezone instead of UTC, or workflow is disabled by branch protection rules. Fix: Replace timezone references with UTC-only CRON, addpermissions: {} block, and ensure default branch has no required status checks blocking workflow execution.---
Exact Error Messages from Console
``` 1. "Workflow disabled due to inactivity" (GitHub Actions dashboard notification after 60 days no pushes)
2. "Schedule event did not trigger workflow run" (Workflow runs page shows no execution at scheduled time)
3. "Branch protection requires status check 'build' to pass before scheduling" (Settings → Branches → Branch protection rules)
4. "CRON schedule invalid: day must be in 0-6 range" (Logs tab when using 7 for Sunday)
5. "Workflow file syntax error: 'schedule' trigger malformed" (GitHub UI validation on YAML commit) ```
---
Broken Code vs. Exact Fix
Issue 1: Timezone-Aware CRON (Most Common)
❌ BROKEN: ```yaml name: Daily Sync on: schedule: # Trying to run at 2 AM EST (doesn't work!) - cron: '0 2 * * *' # GitHub interprets as UTC, runs at 7 AM UTC
jobs: sync: runs-on: ubuntu-latest steps: - run: echo "Syncing data" ```
✅ FIXED: ```yaml name: Daily Sync on: schedule: # Explicitly UTC: runs at 2 AM UTC (equivalent to 9 PM EST previous day) - cron: '0 2 * * *'
permissions: contents: read # Required for scheduled workflows
jobs: sync: runs-on: ubuntu-latest steps: - run: echo "Syncing data at 2 UTC" ```
Key difference: GitHub Actions ALWAYS interprets cron as UTC, never EST/local. If you need 2 AM EST, calculate backwards: 2 AM EST = 7 AM UTC = cron: '0 7 * * *'
Issue 2: Disabled Workflow (Inactivity)
❌ BROKEN: ```yaml
File exists but hasn't run in 60+ days due to no repository activity
name: Backup on: schedule: - cron: '0 3 * * *' jobs: backup: runs-on: ubuntu-latest steps: - run: backup.sh ```✅ FIXED: ```yaml name: Backup on: schedule: - cron: '0 3 * * *' # Add manual trigger to keep workflow "active" workflow_dispatch:
jobs: backup: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # Counts as activity - run: backup.sh ```
Why: GitHub disables scheduled workflows after 60 days of no repository activity (pushes, PRs, manual triggers). Adding workflow_dispatch allows you to manually trigger anytime, resetting the inactivity timer.
Issue 3: Branch Protection Blocking Execution
❌ BROKEN: ```yaml
Settings → Branches → Branch protection rules
"Require status checks to pass before merging" = enabled
Workflow runs but NEVER EXECUTES because it can't report status
name: Test on: schedule: - cron: '0 4 * * 1-5' jobs: test: runs-on: ubuntu-latest steps: - run: npm test ```
✅ FIXED: ```yaml name: Test on: schedule: - cron: '0 4 * * 1-5'
permissions: contents: read # Add explicit permissions for scheduled workflows statuses: write
jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm test ```
AND in GitHub UI: Settings → Branches → Branch protection rule → uncheck "Require status checks to pass" OR add your workflow as an exception.
---
Invalid CRON Format Examples
| ❌ Broken | ✅ Fixed | Reason |
|-----------|----------|--------|
| 0 2 * * 7 | 0 2 * * 0 | Sunday is 0, not 7 |
| 0 14:30 * * * | 0 14 * * * (at 2:30 PM UTC) | Only HH format, no minutes in hour field |
| 0 0 31 2 * | 0 0 1 3 * | Feb never has 31 days; manually handle |
| 0 2 * * MON | 0 2 * * 1 | String names not supported; use 0-6 |
---
Still Broken? Check These Too
1. [Workflow syntax errors in YAML](/?guide=github-actions-yaml-validation) — Validate .github/workflows/*.yml with yamllint locally before pushing. GitHub's UI validator misses edge cases.
2. [Default branch mismatch](/?guide=github-actions-branch-selection) — Scheduled workflows ONLY run on your default branch (usually main). If your workflow file is only on dev, it won't trigger.
3. GitHub free plan quotas — Free accounts get 2,000 Actions minutes/month. If quota exceeded, scheduled workflows are silently skipped. Check Settings → Billing → Usage.
---
Verification Checklist
permissions: { contents: read } blockif: github.event_name == 'push' limiting to push eventsworkflow_dispatch added---
Official Resources
---
Found a Different Variation?
Drop it in the comments—include the error message, your YAML snippet, and how you fixed it. We'll add the top fixes to this guide.