Skip to content
Latchkey

GITHUB_TOKEN and default-branch context on scheduled runs in CI

A scheduled run always executes with the default branch checked out and uses the repository default GITHUB_TOKEN permissions. github.ref is the default branch, so steps expecting a PR or feature-branch context behave differently under a cron.

What this error means

A step that worked on push fails on the schedule because github.ref is refs/heads/main, the checked-out SHA is default-branch HEAD, or a token permission the push flow had is missing.

GitHub Actions context
# On schedule:
github.ref      = refs/heads/main
github.sha      = <default-branch HEAD>
github.event_name = schedule
# A step that read github.head_ref (PR-only) is now empty.

Common causes

Schedule uses the default branch ref

The cron checks out the default branch, so github.ref and github.sha point there, not at any feature branch.

Default token permissions apply

Scheduled runs get the repository default GITHUB_TOKEN scope; if a job needs write, you must grant it with permissions.

How to fix it

Set explicit permissions for the scheduled job

  1. Declare the exact permissions the scheduled job needs.
  2. Avoid relying on PR-only context values under a schedule.
  3. Check github.event_name == 'schedule' where behavior must differ.
.github/workflows/nightly.yml
permissions:
  contents: read
  issues: write   # e.g. for a scheduled stale-issue job

Branch behavior on the event name

Use the event name to switch logic so a cron does not run PR-only steps that assume head_ref.

.github/workflows/nightly.yml
- if: github.event_name == 'schedule'
  run: echo "scheduled path on default branch"

How to prevent it

  • Grant least-privilege permissions explicitly for cron jobs.
  • Do not rely on PR-only context under a schedule.
  • Test scheduled logic with workflow_dispatch on the default branch.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →