Skip to content

Rate Limit Errors

DodaTech 2 min read

title: "Rate Limit Errors — Handling 429 Too Many Requests" description: "429 Too Many Requests errors occur when a client exceeds the rate limit, and responses include Retry-After headers and current rate limit status." date: 2026-06-28 lastmod: 2026-06-28 weight: 19 tags: [apis, error-handling] }

Rate limit errors return 429 when a client exceeds the allowed request rate, with Retry-After headers, current usage stats, and guidance on handling limits.

What You'll Learn

  • Implementing rate limit error responses
  • Using Retry-After header correctly
  • Communicating rate limit status

Why It Matters

Rate limits protect API resources. Clear rate limit errors help clients implement backoff strategies without overwhelming your servers.

Code Examples

// Rate limit error response
{
  "error": "RATE_LIMIT_EXCEEDED",
  "message": "You have exceeded the rate limit of 100 requests per minute",
  "retry_after_seconds": 30,
  "limit": 100,
  "remaining": 0,
  "reset_at": "2024-01-15T10:30:00Z"
}
# Rate limit error middleware
class RateLimitExceeded(Exception):
    def __init__(self, limit, retry_after):
        self.limit = limit
        self.retry_after = retry_after

@app.errorhandler(RateLimitExceeded)
def handle_rate_limit(error):
    response = jsonify({
        "error": "RATE_LIMIT_EXCEEDED",
        "message": f"Rate limit of {error.limit} per minute exceeded",
        "retry_after_seconds": error.retry_after,
        "limit": error.limit,
        "remaining": 0
    })
    response.status_code = 429
    response.headers['Retry-After'] = str(error.retry_after)
    response.headers['X-RateLimit-Limit'] = str(error.limit)
    response.headers['X-RateLimit-Remaining'] = '0'
    response.headers['X-RateLimit-Reset'] = str(int(time.time()) + error.retry_after)
    return response
// Client-side handling (exponential backoff)
async function fetchWithRetry(url, options) {
  const res = await fetch(url, options);
  if (res.status === 429) {
    const retryAfter = res.headers.get('Retry-After') || 60;
    await new Promise(r => setTimeout(r, retryAfter * 1000));
    return fetchWithRetry(url, options);
  }
  return res;
}

Common Mistakes

1. Returning 429 Without Retry-After

Always include Retry-After so clients know when to retry.

2. Not Including Rate Limit Headers

Rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) help clients manage their usage.

3. No Grace Period for Burst

Allow short bursts above the limit to handle legitimate traffic spikes.

4. Throttling Without Warning

Don't go from 200 to 429 on the next request. Add a warning header at 80% capacity.

5. Reset Timing Inconsistency

The reset_at time should match the Retry-After calculation.

Practice Questions

  1. What status code indicates rate limiting?
  2. What is the purpose of the Retry-After header?
  3. What rate limit headers help clients manage usage?
  4. How should clients handle 429 responses?
  5. Why should you warn clients before rate limiting?

Answers:

  1. 429 Too Many Requests.
  2. It tells the client how many seconds to wait before retrying.
  3. X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
  4. Implement exponential backoff with a maximum delay.
  5. So clients can slow down before being blocked, improving user experience.

Challenge: Implement a rate limiter that returns structured 429 responses with Retry-After headers. Include a warning header when the client reaches 80% of the limit.

FAQ

Should I use 429 or 503 for rate limiting?

: 429 is the standard code for rate limiting. Use 503 for server overload.

What is exponential backoff?

: Doubling the wait time after each failed retry (1s, 2s, 4s, 8s) to avoid overwhelming the server.

Can I have different rate limits per endpoint?

: Yes. Document per-endpoint limits and return appropriate error messages.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro