HTTP

425 - Too Early

Hitting a 425 Too Early means the server rejected your request because it might be a replay attack—the request arrived too early in a timing window, or replay protection detected a potential duplicate. This client-side error (4xx) is used in HTTP/2 Server Push and HTTP/3 to prevent replay attacks. Most common when requests are sent too quickly after a previous request, but also appears when timing windows are violated, nonces are reused, or replay protection mechanisms trigger.

#Common Causes

  • Frontend: Request sent too early after previous request. Missing or invalid timestamp in request. Nonce reused or missing. Request timing violates server window. Rapid retries trigger replay protection.
  • Backend: Replay attack prevention middleware detects early request. Timing window validation fails. Nonce validation rejects request. HTTP/2 push timing issue. Server replay protection active.
  • Infrastructure: Load balancer replay protection. API gateway timing validation. WAF replay attack detection. Network timing issues cause early arrival.

Solutions

  1. 1Step 1: Diagnose - Check DevTools Network tab Request timing—review request timestamps. Verify if requests are sent too quickly. Check Retry-After header. Review request timing patterns.
  2. 2Step 2: Diagnose - Server logs show timing window violations. Review replay protection configuration. Check nonce validation. Examine timing window settings.
  3. 3Step 3: Fix - Client-side: Wait for Retry-After duration before retrying. Add proper timestamps to requests. Generate unique nonces for each request. Implement proper request timing.
  4. 4Step 4: Fix - Server-side: Return 425 with Retry-After header. Configure appropriate timing windows. Implement nonce validation. Add replay protection logging.
  5. 5Step 5: Fix - Infrastructure: Review load balancer timing settings. Configure API gateway replay protection. Adjust WAF timing rules. Monitor network latency.

</>Code Examples

Fetch API: Handle 425 with Timing and Nonces
1// Client-side: Handle 425 by adding timing information
2async function sendRequestWithTiming(data) {
3  const timestamp = Date.now();
4  const nonce = crypto.randomUUID(); // Generate unique nonce for each request
5  
6  const response = await fetch('/api/endpoint', {
7    method: 'POST',
8    headers: {
9      'Content-Type': 'application/json',
10      'X-Request-Timestamp': timestamp.toString(),
11      'X-Request-Nonce': nonce,
12    },
13    body: JSON.stringify(data),
14  });
15  
16  if (response.status === 425) {
17    // Request too early - wait for Retry-After
18    const retryAfter = parseInt(response.headers.get('Retry-After') || '1');
19    console.log(`Request too early, waiting ${retryAfter} seconds...`);
20    
21    await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
22    
23    // Retry with updated timestamp and new nonce
24    return sendRequestWithTiming(data);
25  }
26  
27  return response.json();
28}
29
30// Prevent rapid retries that trigger 425
31class RequestThrottler {
32  constructor(minDelay = 1000) {
33    this.minDelay = minDelay;
34    this.lastRequestTime = 0;
35  }
36  
37  async throttle(fn) {
38    const now = Date.now();
39    const timeSinceLastRequest = now - this.lastRequestTime;
40    const delay = Math.max(0, this.minDelay - timeSinceLastRequest);
41    
42    if (delay > 0) {
43      await new Promise(resolve => setTimeout(resolve, delay));
44    }
45    
46    this.lastRequestTime = Date.now();
47    return fn();
48  }
49}
50
51const throttler = new RequestThrottler(1000); // 1 second minimum between requests
52await throttler.throttle(() => sendRequestWithTiming(data));
Express.js: Replay Attack Prevention
1// Server-side: Implement replay attack prevention
2const express = require('express');
3const crypto = require('crypto');
4const app = express();
5
6// Store used nonces (in production, use Redis)
7const usedNonces = new Set();
8const NONCE_TTL = 5 * 60 * 1000; // 5 minutes
9
10// Clean up old nonces periodically
11setInterval(() => {
12  // In production, use Redis TTL instead
13  usedNonces.clear(); // Simplified - should track timestamps
14}, NONCE_TTL);
15
16// Replay protection middleware
17const preventReplay = (req, res, next) => {
18  const timestamp = parseInt(req.headers['x-request-timestamp'] || '0');
19  const nonce = req.headers['x-request-nonce'];
20  const now = Date.now();
21  
22  // Check if nonce is provided
23  if (!nonce) {
24    return res.status(425)
25      .set('Retry-After', '1')
26      .json({
27        error: 'Too Early',
28        message: 'Request must include X-Request-Nonce header',
29      });
30  }
31  
32  // Check if nonce was already used (replay attack)
33  if (usedNonces.has(nonce)) {
34    return res.status(425)
35      .set('Retry-After', '60')
36      .json({
37        error: 'Too Early',
38        message: 'Request replay detected',
39      });
40  }
41  
42  // Check if request is too early (within timing window)
43  const timeDiff = now - timestamp;
44  const TIMING_WINDOW = 5000; // 5 seconds
45  
46  if (timeDiff < 0 || timeDiff > TIMING_WINDOW) {
47    return res.status(425)
48      .set('Retry-After', '1')
49      .json({
50        error: 'Too Early',
51        message: 'Request timing window violation',
52        timingWindow: TIMING_WINDOW,
53        timeDiff: timeDiff,
54      });
55  }
56  
57  // Mark nonce as used
58  usedNonces.add(nonce);
59  
60  // Clean up nonce after TTL
61  setTimeout(() => {
62    usedNonces.delete(nonce);
63  }, NONCE_TTL);
64  
65  next();
66};
67
68// Apply to sensitive endpoints
69app.post('/api/payment', preventReplay, express.json(), (req, res) => {
70  // Process payment with replay protection
71  res.json({ success: true });
72});
Nginx: Pass Timing Headers
1# Nginx: Pass timing headers to backend
2server {
3    listen 80;
4    server_name api.example.com;
5    
6    location /api/ {
7        proxy_pass http://backend;
8        proxy_set_header Host $host;
9        proxy_set_header X-Real-IP $remote_addr;
10        
11        # Pass timing headers to backend
12        proxy_set_header X-Request-Timestamp $http_x_request_timestamp;
13        proxy_set_header X-Request-Nonce $http_x_request_nonce;
14        
15        # Backend handles replay protection
16    }
17}

Related Errors

Provider Information

This error code is specific to HTTP services. For more information, refer to the official HTTP documentation.

425 - Too Early | HTTP Error Reference | Error Code Reference