425 Too Early
The server is unwilling to risk processing a request that might be replayed.
Meaning & Description
Common Causes
- The client sent a state-changing POST request using TLS Early Data.
- The server is configured to reject all 0-RTT traffic for sensitive API endpoints.
- A proxy between the client and server forwarded a 0-RTT request that the backend deemed unsafe.
How to fix a 425 error
- If you are writing a client, ensure your HTTP library handles 425 by automatically retrying the request without the Early-Data header.
- If you are configuring a server, ensure idempotency for endpoints accepting Early Data, or configure the reverse proxy to automatically return 425 for non-GET requests.
- Check for the presence of the `Early-Data: 1` header in incoming requests.
- Disable 0-RTT on the server if your application architecture cannot handle replay attacks safely.
Browser & SEO Behaviour
Browser Behavior
Modern browsers (like Chrome and Firefox) that support TLS 1.3 0-RTT will transparently handle a 425 response by automatically retrying the request once the TLS handshake is fully complete, invisible to the user.
SEO Impact
No SEO impact. Search engine crawlers typically do not use 0-RTT for state-changing operations, and they automatically retry on 425.
CDN Behavior
CDNs like Cloudflare support 0-RTT. They can be configured to automatically reject non-GET requests in Early Data with a 425, or forward the `Early-Data` header to the origin server to make the decision.
Code Examples
POST /api/transfer HTTP/1.1
Host: api.example.com
Early-Data: 1
Content-Type: application/json
{"amount": 1000}app.post('/api/transfer', (req, res) => {
if (req.headers['early-data'] === '1') {
return res.status(425).send("Too Early: Request might be replayed");
}
// Process transfer safely
res.send("Transfer complete");
});@app.post("/api/checkout")
def checkout(request: Request):
if request.headers.get("Early-Data") == "1":
raise HTTPException(status_code=425, detail="Too Early")
return {"status": "Processing"}func checkoutHandler(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Early-Data") == "1" && r.Method != "GET" {
http.Error(w, "Too Early", 425)
return
}
w.WriteHeader(http.StatusOK)
}[HttpPost("checkout")]
public IActionResult Checkout() {
if (Request.Headers.TryGetValue("Early-Data", out var earlyData) && earlyData == "1") {
return StatusCode(425, "Too Early to process safely.");
}
return Ok();
}curl -X POST https://api.example.com/data \
-H "Early-Data: 1" \
-d '{"action":"buy"}' \
-iRaw HTTP Response Example
HTTP/1.1 425 Too Early
Content-Type: text/plain
Content-Length: 46
Too Early: TLS 0-RTT replay protection active.Real-world Examples
Frequently Asked Questions
What is TLS 1.3 Early Data (0-RTT)?
0-RTT (Zero Round Trip Time) is a feature of TLS 1.3 that allows a client to send HTTP request data along with the initial TLS handshake, saving connection time for returning visitors.
Why is 0-RTT dangerous for POST requests?
Because 0-RTT data can be intercepted by an attacker and re-sent (replayed) to the server. If the request was a money transfer, a replay attack could cause the transfer to happen twice.
Do users see a 425 error screen?
No. Browsers are programmed to intercept a 425 response and automatically re-send the request securely once the connection is fully established. It happens instantly in the background.
How does a server know a request is Early Data?
The proxy or web server decrypting the TLS connection typically injects an 'Early-Data: 1' HTTP header before passing the request to the backend application.
Should I disable 0-RTT entirely?
Not necessarily. 0-RTT is excellent for speeding up GET requests (like loading images or HTML). You only need to protect state-changing endpoints (POST, PUT, DELETE).
Did You Know?
The 425 status code was introduced specifically to address the security trade-offs of TLS 1.3's performance optimizations.
A replay attack doesn't require the attacker to decrypt the payload; they just copy the encrypted bytes and hurl them at the server again.
Prior to RFC 8470, 425 was unofficially proposed as 'Unordered Collection' in WebDAV, but that draft was abandoned.
Developer Tips
- Rely on your reverse proxy (Nginx, HAProxy, Cloudflare) to handle 0-RTT and 425 responses so your application code doesn't have to worry about TLS specifics.
- If you must handle it in application logic, look for the 'Early-Data: 1' header and return 425 immediately for any non-idempotent operation.
- Ensure your APIs are properly RESTful. If a GET request changes state, 0-RTT could cause unintended side effects during replay.
Interview Questions
These are questions you might face in a backend or API design interview that touch on HTTP 425.
What problem does the HTTP 425 Too Early status code solve?
It mitigates replay attacks introduced by TLS 1.3 0-RTT (Early Data). It tells the client that the server refuses to execute a potentially unsafe, state-changing request until the connection is fully secure.
How should an HTTP client behave when receiving a 425 status code?
The client should automatically re-attempt the exact same request after the TLS handshake has completed, without prompting the user.
Is it safe to accept 0-RTT Early Data for GET requests?
Generally yes, assuming the GET request is strictly idempotent and read-only, as REST principles dictate. Replaying a safe read operation has no adverse side effects.
Common Interview Mistakes
- Confusing 'Too Early' with rate limiting ('Too Many Requests' - 429) or premature execution.
- Failing to associate 425 with TLS 1.3, 0-RTT, and replay attacks.
- Assuming the client must display an error message to the user upon receiving a 425.