Fixing "GitHub API Rate Limit Exceeded" for Issue Alerts
As a solo founder or part of a small, agile team, every single issue alert is critical. Missing a notification about a new bug report, a critical dependency update, or a customer's urgent request can have disproportionately large consequences. So, when you see that dreaded "GitHub API rate limit exceeded" error pop up, preventing your issue alerts from firing, it's not just an annoyance – it's a direct threat to your operational efficiency and responsiveness.
You're trying to keep your product running smoothly, your users happy, and your codebase healthy. The last thing you need is your tooling failing silently because of an API constraint you didn't anticipate. This article will walk you through practical, engineer-focused strategies to diagnose, prevent, and fix GitHub API rate limit issues, ensuring your issue alerts always reach you.
Understanding GitHub API Rate Limits
First, let's understand why these limits exist. GitHub, like any large API provider, imposes rate limits to prevent abuse, ensure fair usage across all users, and maintain the stability and performance of their services.
GitHub generally distinguishes between two main types of API requests:
- Unauthenticated Requests: These are requests made without any authentication token. They are heavily rate-limited, typically to 60 requests per hour for a given IP address. You'll hit this very quickly if you're doing anything programmatic.
- Authenticated Requests: These requests are made using a Personal Access Token (PAT), OAuth token, or GitHub App installation token. The limits are significantly higher, usually 5,000 requests per hour for PATs/OAuth, and even higher for GitHub Apps (often 15,000 requests per hour for a specific endpoint, but the overall limit is more complex and based on the number of repositories and installations).
You can always check your current rate limit status by hitting the /rate_limit endpoint. This is crucial for debugging:
curl -i https://api.github.com/rate_limit
If you're authenticated, add your token:
curl -i -H "Authorization: token YOUR_GITHUB_PAT" https://api.github.com/rate_limit
The response headers will tell you:
X-RateLimit-Limit: The maximum number of requests you can make in the current window.X-RateLimit-Remaining: The number of requests remaining in the current window.X-RateLimit-Used: The number of requests already used in the current window.X-RateLimit-Reset: The UTC epoch seconds at which the current rate limit window resets.
Common scenarios where you might hit limits include: aggressive CI/CD pipelines fetching repository data, bots automating tasks, multiple integrations (e.g., Slack, Jira, custom scripts) all polling GitHub, or custom issue alert systems that poll too frequently.
Strategy 1: Authenticate Your Requests Properly
This is the most fundamental and often overlooked step. If your issue alert system or any script interacting with GitHub isn't authenticating, you're operating under the most restrictive limits.
Personal Access Tokens (PATs)
For most solo founders and small teams, using a Personal Access Token is the easiest way to get started.
- Generate a PAT: Go to your GitHub profile settings, then "Developer settings" > "Personal access tokens" > "Tokens (classic)" or "Fine-grained tokens". Generate a new token.
- Scopes: Carefully select the minimum necessary scopes. For reading issues and comments,
repo(or more granularissuesandpull_requestsif using fine-grained tokens) is usually sufficient. Avoid granting broader permissions than necessary. - Usage: Pass the token in the
Authorizationheader as atoken(for classic PATs) orBearer(for fine-grained PATs) when making API requests.
Example 1: Using a PAT with curl to fetch issues
Let's say you have a script that checks for new issues. Without authentication, you'd quickly hit limits. With a PAT, you get 5000 requests/hour.
# Store your PAT securely, e.g., in an environment variable
export GITHUB_PAT="ghp_YOUR_VERY_SECURE_TOKEN"
# Fetch open issues for a repository
curl -H "Authorization: token $GITHUB_PAT" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/octocat/Spoon-Knife/issues?state=open"
Security Pitfall: Never hardcode PATs directly into your scripts or commit them to version control. Use environment variables, a secrets manager (like AWS Secrets Manager, HashiCorp Vault), or a .env file that's ignored by Git.
GitHub Apps
For more complex integrations, especially if you need to interact with multiple repositories or organizations, GitHub Apps offer a more robust solution. They have their own, often higher, rate limits and provide much more granular permission control. While setup is more involved, they are the recommended approach for production-grade integrations. You create an app, install it on repositories, and then use the app's private key to generate installation tokens, each with its own rate limit bucket.
Strategy 2: Optimize Your API Calls
Even with authentication, inefficient API usage can still lead to rate limit issues.
Webhooks Over Polling
This is perhaps the single most important optimization for issue alerts. Do not poll the GitHub API repeatedly to check for new issues or comments. This is incredibly inefficient and will quickly exhaust your limits.
Instead, use GitHub Webhooks. GitHub can send an HTTP POST payload to your configured URL whenever specific events occur (e.g., issues, issue_comment, pull_request).
- Configure a Webhook: In your repository settings, go to "Webhooks" and add a new webhook.
- Payload URL: This is your server's endpoint that will receive the events.
- Content type: Usually
application/json. - Secret: Set a secret token. GitHub will use this to sign the payload, allowing you to verify that the request truly came from GitHub.
- Events: Select only the events you care about (e.g., "Issues", "Issue comment").
When GitHub sends an issues event (e.g., opened, edited, closed), your endpoint receives the full event payload. You can then process this payload to trigger your alert without making any additional GitHub API calls.
Pitfall: You need a publicly accessible endpoint to receive webhooks. For local development, tools like ngrok can expose your local server. For production, ensure your server is robust and secure.
Conditional Requests (ETags)
If you must poll for some reason (e.g., fetching profile data that changes infrequently), use conditional requests. GitHub sends an ETag header in its responses. On subsequent requests for the same resource, you can send this ETag back in an If-None-Match header.
If the resource hasn't changed, GitHub will respond with a 304 Not Modified status code and an empty body. Crucially, this request does not count against your rate limit.
Example 2: Using If-None-Match with curl
```bash
First request
curl -i -H "Authorization: token $GITHUB_PAT" \ -H "Accept: application/vnd.github.v3+json