429 Too Many Requests
The user has sent too many requests in a given amount of time (rate limiting).
Meaning & Description
Common Causes
- Aggressive polling or infinite loops in client application code.
- Insufficient API rate limits for a legitimate high-traffic application.
- Malicious behavior such as DDoS attacks or credential stuffing.
How to fix a 429 error
- Check the `Retry-After` response header to see how many seconds you need to wait before retrying.
- Inspect custom rate limit headers (e.g., `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`) to understand the quota rules.
- Implement exponential backoff and jitter in your application's retry logic.
- If you are a legitimate high-volume user, contact the API provider to request a limit increase or upgrade your pricing tier.
Browser & SEO Behaviour
Browser Behavior
Browsers treat 429 like any other client error and simply display the response body. If an automated script running in the browser triggers a 429, the JavaScript fetch/XHR promise resolves normally, but the status will be 429, which the developer must handle manually.
SEO Impact
If a search engine crawler hits a 429, it will slow down its crawl rate. Returning a `Retry-After` header helps crawlers know exactly when it is safe to return without penalizing the site's ranking.
CDN Behavior
CDNs and WAFs frequently issue 429 responses directly to clients to protect origin servers from DDoS attacks or scraping, terminating the request at the edge.
Code Examples
GET /api/v1/users HTTP/1.1
Host: api.example.com
Authorization: Bearer my-tokenconst rateLimit = require('express-rate-limit');
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per window
standardHeaders: true, // Return rate limit info in the RateLimit-* headers
legacyHeaders: false, // Disable the X-RateLimit-* headers
message: { error: "Too Many Requests, please try again later." }
});
app.use('/api/', apiLimiter);from fastapi import Request, HTTPException
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(429, _rate_limit_exceeded_handler)
@app.get("/data")
@limiter.limit("5/minute")
def get_data(request: Request):
return {"data": "This is protected by rate limiting"}import "golang.org/x/time/rate"
var limiter = rate.NewLimiter(1, 3) // 1 request per second, burst of 3
func limitMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !limiter.Allow() {
w.Header().Set("Retry-After", "2")
http.Error(w, "Too Many Requests", 429)
return
}
next.ServeHTTP(w, r)
})
}// Program.cs setup required for Microsoft.AspNetCore.RateLimiting
builder.Services.AddRateLimiter(options => {
options.AddFixedWindowLimiter("Fixed", opt => {
opt.PermitLimit = 100;
opt.Window = TimeSpan.FromMinutes(1);
opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
opt.QueueLimit = 0;
});
options.OnRejected = async (context, token) => {
context.HttpContext.Response.StatusCode = 429;
await context.HttpContext.Response.WriteAsync("Rate limit exceeded.", token);
};
});curl -i https://api.twitter.com/2/tweets
# Response contains X-RateLimit-* headersRaw HTTP Response Example
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1672531260
{
"error": "Rate limit exceeded. Please wait 60 seconds before retrying."
}Real-world Examples
Frequently Asked Questions
What does HTTP Error 429 mean?
HTTP 429 Too Many Requests means you have exceeded the number of allowed requests for a given time period on a specific server or API.
How do I bypass a 429 error?
You cannot typically 'bypass' it. The correct approach is to wait the amount of time specified in the `Retry-After` header. Implementing an exponential backoff retry strategy in your code is highly recommended.
Is 429 a ban?
No, a 429 is a temporary pause (rate limit). However, if you aggressively ignore 429 responses, some services may escalate to a permanent ban (403 Forbidden).
What is the Retry-After header?
It's an HTTP header that tells the client how long to wait before making another request. It can be formatted as an integer representing seconds, or a specific HTTP date.
What is exponential backoff?
Exponential backoff is a standard error-handling strategy where an application waits longer between each subsequent retry attempt (e.g., 1s, 2s, 4s, 8s) to avoid overwhelming the server.
Did You Know?
Before 429 was standardized in 2012 (RFC 6585), Twitter famously returned a 420 Enhance Your Calm status code for rate limiting.
There is a standardized draft for generic RateLimit headers (`RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset`), aiming to replace the varied `X-RateLimit-*` vendor-specific headers.
A 429 does not necessarily apply globally; it might apply to a specific IP, a specific API token, or a specific endpoint.
Developer Tips
- Always return a `Retry-After` header with a 429 response. It makes client integration much easier and helps automated tools back off efficiently.
- Include informational headers (like `X-RateLimit-Remaining`) even on successful 200 responses, so clients can throttle themselves proactively.
- Use a distributed cache like Redis to track rate limits if you run multiple instances of your API backend.
- Consider implementing distinct rate limits for authenticated vs. unauthenticated users.
Interview Questions
These are questions you might face in a backend or API design interview that touch on HTTP 429.
What status code is used for API rate limiting, and what header should ideally accompany it?
The 429 Too Many Requests status code is used for rate limiting. It should ideally be accompanied by the `Retry-After` header.
What is the difference between 429 Too Many Requests and 503 Service Unavailable?
429 is a client error indicating a specific client is making too many requests and being throttled. 503 is a server error indicating the server is overloaded globally and cannot handle requests from *anyone*.
How would you design a robust client application to handle 429 responses?
I would implement an interceptor or middleware that catches 429s, reads the `Retry-After` header, pauses execution for that duration, and then automatically retries the request. I'd also add exponential backoff with jitter as a fallback.
Common Interview Mistakes
- Saying that 429 is a server crash or database failure.
- Confusing rate limiting with DDoS protection at the network layer (layer 3/4). 429 is an application layer (layer 7) response.
- Failing to mention the `Retry-After` header or the concept of exponential backoff.