Error 429 · Rate Limit Exceeded

Root Causes & 60-Second Solutions

Error 429 Rate Limit Exceeded occurs when your application makes too many requests to an API within a specific time window. This comprehensive guide provides immediate solutions using CLI tools, API adjustments, and retry strategies to resolve rate limiting issues in under 60 seconds.

Root Cause

Rate limiting errors typically stem from one or more of these underlying issues:

  • Burst requests: Sending too many requests in a short time period
  • Missing rate limiting: No client-side throttling implementation
  • Insufficient quotas: API plan limits exceeded
  • Concurrent processes: Multiple instances hitting the same endpoint
  • Poor retry logic: Aggressive retries without backoff

The most common scenario is applications that don't implement proper request spacing, leading to sudden spikes that trigger API rate limiters.

Fix in CLI

Use Gemini CLI to automatically implement rate limiting fixes in your codebase:

gemini fix "429 rate limit exceeded"

For automatic retry logic implementation:

gemini generate "exponential backoff retry logic for API calls"

The CLI will analyze your code and suggest specific implementations based on your tech stack and API patterns.

API Adjustments

Implement client-side request throttling to prevent rate limit errors:

JavaScript/Node.js

const rateLimiter = { queue: [], running: false, delay: 1000, // 1 second between requests async add(apiCall) { return new Promise((resolve, reject) => { this.queue.push({ apiCall, resolve, reject }); this.process(); }); }, async process() { if (this.running || this.queue.length === 0) return; this.running = true; while (this.queue.length > 0) { const { apiCall, resolve, reject } = this.queue.shift(); try { const result = await apiCall(); resolve(result); } catch (error) { reject(error); } await new Promise(resolve => setTimeout(resolve, this.delay)); } this.running = false; } };

Python

import time import requests from functools import wraps def rate_limit(calls_per_second=1): min_interval = 1.0 / calls_per_second last_called = [0.0] def decorator(func): @wraps(func) def wrapper(*args, **kwargs): elapsed = time.time() - last_called[0] left_to_wait = min_interval - elapsed if left_to_wait > 0: time.sleep(left_to_wait) ret = func(*args, **kwargs) last_called[0] = time.time() return ret return wrapper return decorator @rate_limit(calls_per_second=2) def api_call(): return requests.get('https://api.example.com/data')

Retry Logic

Implement exponential backoff to handle temporary rate limits gracefully:

async function retryWithBackoff(apiCall, maxRetries = 3) { for (let attempt = 0; attempt <= maxRetries; attempt++) { try { return await apiCall(); } catch (error) { if (error.status === 429 && attempt < maxRetries) { const delay = Math.pow(2, attempt) * 1000; // Exponential backoff console.log(`Rate limit hit, retrying in ${delay}ms`); await new Promise(resolve => setTimeout(resolve, delay)); continue; } throw error; } } } // Usage const result = await retryWithBackoff(() => fetch('https://api.example.com/data') .then(response => { if (response.status === 429) { throw { status: 429, message: 'Rate limited' }; } return response.json(); }) );

This implementation waits progressively longer between retries: 1s, 2s, 4s, preventing further rate limit violations while allowing temporary limits to reset.

Common Pitfalls

Avoid these mistakes that can worsen rate limiting issues:

  • Immediate retries: Retrying failed requests instantly without delay compounds the problem and may trigger longer rate limit windows
  • Ignoring Retry-After headers: Many APIs provide specific wait times in response headers - always check and respect these values
  • Fixed retry intervals: Using the same delay for all retries doesn't adapt to varying server load conditions
  • No jitter in backoff: Multiple clients using identical backoff timing can create synchronized retry storms
  • Excessive retry attempts: More than 3-5 retries usually indicates a deeper issue that won't resolve with more attempts
  • Missing request deduplication: Duplicate requests waste quota and increase the likelihood of hitting rate limits
  • Poor error handling: Not distinguishing between 429 (retriable) and 4xx errors (permanent failures) leads to wasted retry attempts