← Back to Docs

GitHub Actions Cron Delayed or Skipped? Run It on Time

GitHub documents that on: schedule runs can be delayed when Actions is busy, especially at the start of every hour, and that some queued runs may be dropped. To start a workflow at a set minute, add a workflow_dispatch trigger and have a scheduler call GitHub's dispatch API at that time. The run is queued the moment the call lands, the same as clicking Run workflow.

1. Add a workflow_dispatch trigger

# .github/workflows/nightly.yml
on:
  workflow_dispatch:
    inputs:
      reason:
        description: Why this run started
        required: false
        default: manual

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/nightly.sh

Remove the schedule: block once the outside schedule is in place, so the job does not run twice. The workflow is then no longer a scheduled workflow, so the rule that switches off schedules in public repositories after 60 quiet days (that error, explained) does not apply to it.

2. Create a token that can start the workflow

Create a fine-grained personal access token limited to this one repository, with the Actions repository permission set to Read and write. Give it an expiry date and note it so you can renew it.

3. Schedule the dispatch call in RunLater

  1. Method POST, URL https://api.github.com/repos/OWNER/REPO/actions/workflows/nightly.yml/dispatches
  2. Headers: Accept: application/vnd.github+json, Authorization: Bearer <token>, X-GitHub-Api-Version: 2022-11-28
  3. Body: {"ref": "main", "inputs": {"reason": "scheduled"}}
  4. Schedule: Recurring with any cron down to once a minute, for example 0 2 * * *, in your timezone; or One-time for a single run at an exact date and time
  5. Retries: 3, so a brief GitHub API error is tried again with backoff

GitHub answers a good request with a 2xx status (204 No Content by default), which shows as a success in the RunLater log. A 401 means the token is wrong or expired, 404 a wrong owner, repo or workflow file name (or a token without access), and 422 a ref that does not exist or an input the workflow does not declare. The response body is kept in the log, so the reason is right there.

If you keep on: schedule

  • Pick a minute other than :00, for example 17 * * * *; the top of the hour is the busiest time.
  • Expect a run to start a few minutes late and write the job so a late start is harmless.
  • Keep the workflow file on the default branch; schedules only run from there.

The full side by side is on RunLater vs GitHub Actions scheduled workflows. RunLater Starter is $15/month for 250 scheduled requests and 25,000 runs, after a 14-day trial.

Frequently asked questions

Why is my GitHub Actions cron running late?

GitHub queues on: schedule runs and documents that they can be delayed when Actions is busy, especially at the start of every hour. A run set for 09:00 can start minutes later, and under heavy load some queued runs are dropped.

Why did my scheduled workflow not run at all?

The usual causes: the workflow file is not on the default branch, the workflow was disabled after 60 days without activity in a public repository, it is a fork (schedules are off by default there), or the run was dropped under load.

Can a GitHub Actions schedule run every minute?

No. The shortest interval for on: schedule is every 5 minutes. A workflow_dispatch call can be sent as often as you like, within GitHub API rate limits.

Does a workflow_dispatch run use Actions minutes?

Yes. It is a normal workflow run and is billed like any other run on your plan. RunLater only sends the API call that starts it.