Skip to content
Latchkey

GitHub Actions github-script "secondary rate limit" / 403 Abuse Detection

A github-script step that fires many API calls in quick succession trips GitHub’s secondary (abuse) rate limit and gets 403s. Re-running after a pause usually succeeds, which marks it transient.

What this error means

A loop of API calls (commenting, labeling, dispatching) starts failing partway with a 403 mentioning a secondary rate limit or abuse detection, even though the token has permission.

github-script
RequestError [HttpError]: You have exceeded a secondary rate limit.
Please wait a few minutes before you try again.  (status 403)

Common causes

Too many requests too fast

Bursty write traffic (many comments, labels, or content writes in a tight loop) trips the secondary rate limit, which is separate from the hourly primary limit.

No throttling or backoff

Octokit can retry and throttle, but a hand-rolled loop with no delay or retry will hit the limit and fail hard.

How to fix it

Add delays and retry on 403

Space out write requests and retry with backoff when a secondary limit is hit.

.github/workflows/ci.yml
- uses: actions/github-script@v7
  with:
    script: |
      const sleep = (ms) => new Promise(r => setTimeout(r, ms));
      for (const n of numbers) {
        await github.rest.issues.addLabels({ ...context.repo, issue_number: n, labels: ['triage'] });
        await sleep(1000);   // throttle writes
      }

Batch and reduce request volume

  1. Combine operations where the API supports it to cut request count.
  2. Re-run the job after a short wait - secondary limits clear quickly.
  3. For heavy automation, use the throttling plugin or a queue instead of a tight loop.

How to prevent it

  • Throttle write-heavy github-script loops with small delays.
  • Retry on secondary-rate-limit 403s with backoff.
  • Batch operations to keep request volume low.

Related guides

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