This gist provides a comprehensive solution for handling GitHub API rate limiting in GitHub Actions workflows. It includes retry logic with exponential backoff and support for Personal Access Tokens (PAT) to increase rate limits.
GitHub Actions workflows often fail with rate limiting errors when making API calls:
HTTP request has failed with error "Maximum retry attempts reached"
This happens because:
- The default
GITHUB_TOKEN
has a limit of 1,000 requests/hour - Multiple workflows or API calls can quickly exhaust this limit
- No built-in retry mechanism for rate limit handling
This solution provides:
- Higher Rate Limits: Use Personal Access Token (5,000 requests/hour vs 1,000)
- Automatic Retry: Exponential backoff when rate limits are hit
- Robust Error Handling: Proper handling of different HTTP status codes
- Reusable Script: Can be used across multiple workflows
- Fallback Support: Works with both PAT and default GITHUB_TOKEN
github-api-call.sh
- Main script with rate limiting and retry logictest-github-api.sh
- Test script to verify functionalitysample-workflow.yml
- Example GitHub Actions workflowworkflow-integration.sh
- Sample integration script for workflows
- Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
- Click "Generate new token (classic)"
- Select scopes:
repo
(for private repos) orpublic_repo
(for public repos) - Copy the generated token
- Go to your repository → Settings → Secrets and variables → Actions
- Click "New repository secret"
- Name:
GITHUB_PAT
- Value: Your generated PAT
- Click "Add secret"
# Create directory (if it doesn't exist)
mkdir -p .ci/scripts
# Download the script
curl -o .ci/scripts/github-api-call.sh https://gist.githubusercontent.com/[GIST_ID]/github-api-call.sh
# Make it executable
chmod +x .ci/scripts/github-api-call.sh
env:
GITHUB_PAT: ${{ secrets.GITHUB_PAT }}
steps:
- name: Make GitHub API call
run: |
# Use the script instead of direct curl
.ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/pulls"
Token Type | Requests/Hour | Use Case |
---|---|---|
GITHUB_TOKEN |
1,000 | Default, basic workflows |
Personal Access Token | 5,000 | Higher volume workflows |
GitHub App | 15,000 | Enterprise applications |
The script supports several environment variables:
# Required (one of these)
export GITHUB_PAT="ghp_xxxxxxxxxxxx" # Preferred
export GITHUB_TOKEN="ghs_xxxxxxxxxxxx" # Fallback
# Optional configuration
export MAX_RETRIES=5 # Default: 5
export INITIAL_WAIT=1 # Default: 1 second
./github-api-call.sh "https://api.github.com/repos/owner/repo/pulls"
./github-api-call.sh "https://api.github.com/repos/owner/repo/issues" raw
MAX_RETRIES=10 INITIAL_WAIT=2 ./github-api-call.sh "https://api.github.com/rate_limit"
# Get PR number for current commit
if api_response=$(./github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/commits/${{ github.sha }}/pulls" raw); then
PR_NUMBER=$(echo "$api_response" | jq -r '.[0].number | select(.!=null)')
echo "Found PR: $PR_NUMBER"
fi
Run the test script to verify everything works:
# Set your token
export GITHUB_PAT="your_token_here"
# Run tests
./test-github-api.sh
Expected output:
✅ Basic API call successful
✅ Rate limit check successful
✅ Invalid URL properly rejected
✅ Non-existent endpoint properly handled
- Verify
GITHUB_PAT
secret is set correctly - Check PAT has appropriate permissions
- Monitor rate limit status:
./github-api-call.sh "https://api.github.com/rate_limit"
chmod +x github-api-call.sh
The script provides detailed logging. Check GitHub Actions logs for:
- Retry attempts
- HTTP status codes
- Rate limit information
- Error messages
# Before (prone to rate limiting)
curl -H "Authorization: token $GITHUB_TOKEN" \
"https://api.github.com/repos/$REPO/pulls"
# After (with retry logic)
./github-api-call.sh "https://api.github.com/repos/$REPO/pulls"
if [ -z "$PR_NUMBER" ]; then
if api_response=$(./github-api-call.sh "$API_URL" raw); then
export PR_NUMBER=$(echo "$api_response" | jq -r '.[0].number')
else
echo "Failed to fetch PR number, continuing without it"
fi
fi
for repo in $REPO_LIST; do
echo "Processing $repo..."
./github-api-call.sh "https://api.github.com/repos/$repo/releases/latest"
sleep 1 # Additional rate limiting
done
MIT License - Feel free to use and modify as needed.
Found an issue or have an improvement? Please share your feedback!
Note: This solution has been tested with GitHub Actions and various API endpoints. The exponential backoff strategy effectively handles temporary rate limits while the PAT provides higher baseline limits.