Troubleshooting GitHub API Rate Limit (403/429), Timeout, and 401 Unauthorized Errors
Fix GitHub API 403 rate limits, 429 Too Many Requests, 401 Unauthorized, and timeout errors. Learn to check limit headers and implement robust retry logic.
- HTTP 403 and 429 errors indicate you have hit either primary rate limits (e.g., 5,000 req/hr) or secondary abuse limits; always respect the 'Retry-After' or 'x-ratelimit-reset' headers.
- HTTP 401 Unauthorized usually stems from an expired token, missing OAuth scopes, or an unconfigured SAML SSO authorization for your PAT.
- HTTP 502 Bad Gateway and API timeouts are often caused by retrieving excessively large datasets without pagination or poorly optimized GraphQL queries.
- To mitigate rate limiting permanently, migrate your CI/CD pipelines from Personal Access Tokens (PATs) to GitHub Apps, which offer dynamically scaling limits, and use ETags for conditional requests.
| Method | When to Use | Rate Limit Quota | Risk / Mitigation |
|---|---|---|---|
| Unauthenticated | Quick local testing, simple cURL scripts | 60 requests / hour / IP | High risk of IP blocking. Only for trivial scripts. |
| Personal Access Token (PAT) | Local dev, user-specific automation scripts | 5,000 requests / hour | Moderate. Tokens expire and are tied to a single user's lifecycle. |
| GitHub App Installation | Enterprise CI/CD, organization-wide automation | 15,000+ requests / hour (scales with org size) | Lowest. Tokens are short-lived and permissions are granularly scoped. |
| GraphQL API | Complex data fetching, highly nested resource graphs | 5,000 points / hour (calculated by query complexity) | High risk of 502/Timeout if the query depth and node count are unoptimized. |
Understanding GitHub API Errors
When integrating with the GitHub API—whether building custom CI/CD pipelines, automating repository management, or extracting developer metrics—you will inevitably encounter rate limits and authentication errors. GitHub aggressively protects its infrastructure using primary and secondary rate limits. Understanding how to interpret headers like x-ratelimit-remaining and handle HTTP status codes (401, 403, 429, 502) is essential for building resilient automation systems.
1. HTTP 403 & 429: Primary and Secondary Rate Limits
GitHub's REST API enforces a strict rate limit. If you are unauthenticated, you are restricted to 60 requests per hour per IP address. Authenticated requests using a Personal Access Token (PAT) or OAuth token receive 5,000 requests per hour. GitHub Apps receive a dynamically scaling limit based on the size of the organization.
Primary Rate Limits (HTTP 403 Forbidden)
When you exceed your primary quota, GitHub returns an HTTP 403 status code. The response body will contain a message indicating the rate limit was exceeded (API rate limit exceeded for user ID). Crucially, you must inspect the HTTP response headers to diagnose the issue:
x-ratelimit-limit: Your total allowed requests per hour.x-ratelimit-remaining: The number of requests you have left in the current window.x-ratelimit-reset: The time at which the current rate limit window resets in UTC epoch seconds.
Secondary Rate Limits (HTTP 429 Too Many Requests or 403) Secondary rate limits are abuse detection mechanisms. Even if you have thousands of requests remaining, you can trigger a secondary limit by:
- Making too many concurrent requests.
- Requesting data that is computationally expensive for GitHub to generate.
- Mutating data (POST/PATCH/DELETE) too quickly.
When a secondary limit is hit, you will see an HTTP 429 or 403, accompanied by a Retry-After header. You must pause your requests for the number of seconds specified in this header. Failing to do so may result in an IP-level ban.
2. HTTP 401: Unauthorized Failures
An HTTP 401 response (Requires authentication) means the API token provided is missing, malformed, expired, or lacks the correct scopes to access the requested resource.
Common Root Causes for 401 Errors:
- Expired Tokens: Classic PATs and Fine-Grained PATs often have strict expiration dates. Check your GitHub Developer Settings.
- SAML SSO Enforcement: If your organization uses SAML Single Sign-On, a PAT must be explicitly authorized to access the organization. An unauthorized token will work for public repos but return a 401 or 404 for organizational repos.
- Missing Scopes: The token does not have the necessary permissions (e.g., trying to read
repodata with onlyuserscopes).
3. HTTP 502 Bad Gateway and API Timeouts
Encountering an HTTP 502, 503, or a generic network timeout usually indicates an issue on GitHub's infrastructure, or that your query is too resource-intensive to execute within the designated time limit.
Why Timeouts Happen:
- Massive Payloads: Querying an endpoint that returns a massive amount of data without pagination.
- Complex GraphQL Queries: Highly nested GraphQL queries can exceed the maximum execution time of 10 seconds, resulting in a timeout.
- GitHub Outages: Always check
githubstatus.comto verify if the API is experiencing degraded performance.
Best Practices for Remediation
1. Implement Exponential Backoff with Jitter
Never retry failed API requests in a tight loop. Implement an exponential backoff strategy. If you receive a 429 or 403 due to rate limiting, read the Retry-After or x-ratelimit-reset headers and sleep the executing thread until that time has elapsed. Add random jitter to avoid thundering herd problems.
2. Use Conditional Requests (ETags)
GitHub API supports conditional requests to help you save your rate limit. When you make a request, GitHub returns an ETag header. On subsequent requests, include this value in the If-None-Match header. If the data hasn't changed, GitHub returns an HTTP 304 Not Modified, which does not count against your rate limit quota.
3. Migrate to GitHub Apps For enterprise automation and CI/CD pipelines, migrate away from Personal Access Tokens (PATs) and use a GitHub App. GitHub Apps have significantly higher rate limits (scaling with the organization size up to 15,000+ requests per hour) and provide short-lived, secure installation tokens.
4. Paginate Aggressively
When interacting with REST endpoints that return arrays, use the per_page parameter (maximum 100) and follow the Link headers to navigate pagination safely without timing out the connection.
Frequently Asked Questions
#!/bin/bash
# A robust bash script to interact with GitHub API, checking limits and handling rate limit headers
GITHUB_TOKEN="your_pat_here"
API_URL="https://api.github.com/repos/octocat/hello-world/issues"
# Function to check rate limit proactively
check_rate_limit() {
local response=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/rate_limit)
local remaining=$(echo "$response" | jq '.resources.core.remaining')
local reset=$(echo "$response" | jq '.resources.core.reset')
echo "Remaining requests: $remaining"
if [ "$remaining" -le 5 ]; then
local now=$(date +%s)
local wait_time=$((reset - now + 5))
echo "Rate limit critically low. Sleeping for $wait_time seconds..."
sleep $wait_time
fi
}
# Execute request and handle 403/429
fetch_data() {
check_rate_limit
local status_code=$(curl -s -o /tmp/response.json -w "%{http_code}" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
$API_URL)
if [ "$status_code" -eq 200 ]; then
echo "Success!"
cat /tmp/response.json | jq '.[0].title'
elif [ "$status_code" -eq 401 ]; then
echo "Error 401: Unauthorized. Check your GITHUB_TOKEN and SSO permissions."
elif [ "$status_code" -eq 403 ] || [ "$status_code" -eq 429 ]; then
echo "Error $status_code: Rate limit or secondary abuse limit hit. Check Retry-After headers."
elif [ "$status_code" -eq 502 ] || [ "$status_code" -eq 504 ]; then
echo "Error $status_code: GitHub API timeout or Bad Gateway. Implementing backoff..."
sleep 10
fetch_data
else
echo "Unexpected HTTP status: $status_code"
fi
}
fetch_dataError Medic Editorial
Written by the Error Medic editorial team. We specialize in untangling complex infrastructure issues, API integrations, and CI/CD pipeline optimization for enterprise environments.
Sources
- https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting
- https://docs.github.com/en/rest/guides/best-practices-for-integrators#dealing-with-secondary-rate-limits
- https://docs.github.com/en/graphql/overview/resource-limitations
- https://docs.github.com/en/enterprise-cloud@latest/authentication/authenticating-with-saml-single-sign-on/authorizing-a-personal-access-token-for-use-with-saml-single-sign-on