Discord webhook HTTP 429 rate limit in CI
Discord rate limits per webhook and returns HTTP 429 with a JSON body containing retry_after (seconds) and {"message":"You are being rate limited."}. In CI this triggers when a matrix build posts many messages to the same webhook in a short burst.
What this error means
A Discord notify step returns HTTP 429 with a retry_after value. Some messages post, others fail, correlated with parallel jobs sharing one webhook.
< HTTP/1.1 429 Too Many Requests
{"message": "You are being rate limited.", "retry_after": 1.462, "global": false}Common causes
Many jobs post to one webhook
A matrix or fan-out that fires a webhook per job exceeds the per-webhook limit in a short window.
Immediate retries ignore retry_after
Retrying without waiting the returned retry_after keeps the webhook throttled.
How to fix it
Wait for retry_after before retrying
- Parse
retry_afterfrom the 429 body. - Sleep that many seconds.
- Retry the post once.
ra=$(jq -r '.retry_after // 2' /tmp/body)
sleep "$ra"
# retry the POST oncePost one summary from a final job
Aggregate results and notify once instead of per matrix leg.
notify:
needs: [build]
if: always()
runs-on: ubuntu-latest
steps:
- run: ./scripts/discord-summary.shHow to prevent it
- Send a single aggregated message per workflow run.
- Honor
retry_afterbefore retrying any 429. - Avoid sharing one webhook across many concurrent jobs.