Error Medic

Cloudflare API Timeout: How to Diagnose and Fix 524, 522, and Request Timeout Errors

Fix Cloudflare API timeout errors (524, 522, 408) by tuning origin response times, adjusting Worker CPU limits, and using Cloudflare's retry APIs. Step-by-step

Last updated:
Last verified:
2,200 words
Key Takeaways
  • Cloudflare enforces a hard 100-second origin response timeout on all plans; if your origin does not respond within that window, Cloudflare returns a 524 (A Timeout Occurred) error to the client
  • The Cloudflare REST Management API (api.cloudflare.com) can return 429 Too Many Requests or drop connections due to client-side TCP timeouts when the caller's HTTP client has a shorter timeout than the API response latency under load
  • Cloudflare Workers have a 50 ms CPU time limit on the Free plan and 30 s on Paid; long-running synchronous compute triggers a 1101 Worker threw exception or a silent timeout that manifests as a 524 downstream
  • Quick fix hierarchy: (1) increase origin response time or offload slow work to async queues, (2) set a suitably long HTTP client timeout when calling api.cloudflare.com, (3) split heavy Worker logic into Durable Objects or Queue consumers
Fix Approaches Compared
MethodWhen to UseEstimated Time to ImplementRisk
Increase Cloudflare Proxy Timeout via Page Rule / Config RuleOrigin is legitimately slow (reports, exports, DB queries > 100 s) and you control the zone30 minutesLow — only affects matched paths
Set long timeout in your API client (axios, requests, curl)Your code calls api.cloudflare.com and drops the TCP connection before Cloudflare responds5 minutesLow — client-side change only
Move slow logic to a background job / queueOrigin endpoint does heavy processing synchronously1–3 daysMedium — requires application refactor
Enable Cloudflare Tiered Cache / Cache RulesRepeated identical API calls are timing out due to cache misses on slow origins1 hourLow — additive caching layer
Migrate heavy Worker logic to Durable Objects or QueuesWorker CPU time limit exceeded on Free/Paid plan1–2 daysMedium — architecture change
Upgrade Cloudflare plan for extended timeout limitsEnterprise timeout (6000 s) required for very long-running jobsHours (commercial)Low — plan change
Implement exponential backoff & retry on 524/522Intermittent timeouts due to origin spikes2–4 hoursLow — defensive coding

Understanding Cloudflare API Timeout Errors

The term "Cloudflare API timeout" covers two distinct failure scenarios that are often confused:

  1. Cloudflare acting as a reverse proxy: Your end-users hit your domain and Cloudflare cannot get a response from your origin server within the allowed time window. This produces HTTP 524 A Timeout Occurred or 522 Connection Timed Out.
  2. Your code calling the Cloudflare Management API (https://api.cloudflare.com/client/v4/...): Your HTTP client drops the connection or Cloudflare returns 408 Request Timeout / 429 Too Many Requests before the API call completes.

Both scenarios share a root cause: a mismatch between how long a party is willing to wait and how long the operation actually takes.


Cloudflare Timeout Error Codes at a Glance

Error Code Meaning Where it Originates
522 Connection Timed Out Cloudflare could not complete the TCP handshake to your origin within 15 s Cloudflare edge
523 Origin Is Unreachable DNS or routing failure to origin Cloudflare edge
524 A Timeout Occurred TCP connected but origin did not send an HTTP response within 100 s Cloudflare edge
408 Request Timeout Client too slow sending the request body Cloudflare or origin
1101 Worker threw exception Worker runtime error, often from a timed-out fetch() inside a Worker Cloudflare Workers runtime
429 Too Many Requests Rate limit hit on api.cloudflare.com Cloudflare API

Step 1: Confirm Which Timeout You Are Hitting

Before making any changes, identify the exact error code and origin.

Check browser DevTools or your HTTP client log:

HTTP/1.1 524 A Timeout Occurred
cf-ray: 8a3f1c2d4e5b6a7b-AMS

The cf-ray header confirms Cloudflare is involved. A 524 means Cloudflare reached your origin but your origin stalled.

Check Cloudflare dashboard logs:

  • Go to Analytics & Logs → HTTP Requests in the Cloudflare dashboard.
  • Filter by Edge Status Code = 524 or 522.
  • Note which paths are affected and whether the pattern is consistent or intermittent.

Test origin bypass:

# Call origin directly (replace with your server IP) bypassing Cloudflare
curl -v --max-time 120 -H "Host: yourdomain.com" http://YOUR_ORIGIN_IP/slow-endpoint

If this also times out, the problem is in your application. If it succeeds within 100 s, Cloudflare's timeout window is the constraint.


Step 2: Fix 524 Errors (Origin Doesn't Respond in Time)

Option A — Speed Up the Origin

This is always the preferred fix. Profile the slow endpoint:

# Time the endpoint from the same network as your origin
curl -w "\nTotal: %{time_total}s\n" -o /dev/null -s http://localhost/slow-endpoint

Common culprits:

  • Unindexed database queries — add indexes, use EXPLAIN ANALYZE
  • Synchronous file I/O blocking the event loop (Node.js) — use streams or worker threads
  • External HTTP calls inside the request path — move to async queues (Celery, BullMQ, Cloudflare Queues)
Option B — Extend the Cloudflare Timeout via Config Rules (Pro plan and above)

Cloudflare exposes the proxy_read_timeout setting via Configuration Rules:

  1. Go to Rules → Configuration Rules in the dashboard.
  2. Create a rule matching your slow path (e.g., http.request.uri.path contains "/export").
  3. Set Proxy Read Timeout to up to 6000 seconds (Enterprise) or up to 100 seconds override on Pro.

Alternatively, use the Cloudflare API to create the rule programmatically:

curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/rulesets/phases/http_config_settings/entrypoint" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "rules": [{
      "action": "set_config",
      "action_parameters": {
        "read_timeout": 300
      },
      "expression": "http.request.uri.path contains \"/export\"",
      "description": "Extend timeout for export endpoint"
    }]
  }'

Note: Free plans cannot extend the 100 s limit. You must optimize the origin or upgrade.

Option C — Return 202 Accepted + Poll Pattern

For operations that genuinely take minutes, restructure the API:

  1. Endpoint immediately returns 202 Accepted with a job ID.
  2. Client polls a /jobs/{id}/status endpoint.
  3. Heavy work runs in a background worker.

This eliminates the timeout entirely because no single HTTP response takes long.


Step 3: Fix Cloudflare Management API Timeouts

When your code calls https://api.cloudflare.com/client/v4/... and the connection drops:

Symptom
Error: connect ETIMEDOUT api.cloudflare.com:443
Error: read ECONNRESET
requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='api.cloudflare.com', port=443)
Root Causes
  • Your HTTP client has a default timeout shorter than the API response latency (common defaults: axios = no timeout, requests Python = no timeout, curl = no timeout unless set)
  • Bulk operations (e.g., purging thousands of cache tags) take longer than expected
  • Rate limiting causes the server to queue your request, exceeding client timeout
Fix: Set Explicit Timeouts and Retry Logic

See the code_block section for a complete example. Key principles:

  • Set timeout to at least 30 s for simple calls, 120 s for bulk operations
  • Respect the Retry-After header on 429 responses
  • Use exponential backoff: wait 1 s, 2 s, 4 s, 8 s before retrying

Step 4: Fix Cloudflare Worker Timeouts

Workers on the Free plan get 10 ms CPU time per request (wall-clock: 30 s). Paid plan: 50 ms CPU / 30 s wall-clock. Exceeding these limits produces:

Error 1101: Worker threw exception

or a silent 524 passed through to the client.

Diagnose:

# Use wrangler tail to stream live Worker logs
npx wrangler tail MY_WORKER_NAME --format=pretty

Look for CPU time exceeded or Script execution timed out.

Fix options:

  • Move CPU-heavy work to a Durable Object alarm (runs async, not in request path)
  • Use Cloudflare Queues to defer processing
  • Offload compute to a dedicated microservice via a subrequest with waitUntil()
// Use waitUntil to defer non-critical work past response
export default {
  async fetch(request, env, ctx) {
    const response = new Response('Accepted', { status: 202 });
    ctx.waitUntil(env.MY_QUEUE.send({ url: request.url }));
    return response;
  }
};

Step 5: Monitor and Alert

Set up proactive monitoring so timeouts don't surprise you:

# Cloudflare Analytics API — query 5xx rates for the last hour
curl "https://api.cloudflare.com/client/v4/zones/ZONE_ID/analytics/dashboard?since=-60&until=0" \
  -H "Authorization: Bearer YOUR_API_TOKEN" | \
  jq '.result.totals.requests.http_status | {"524": ."524", "522": ."522"}'

Consider:

  • Cloudflare Health Checks (under Traffic → Health Checks) to get alerted when origin latency exceeds a threshold
  • Cloudflare Notifications → Zone Analytics anomalies for 5xx spike alerts
  • Grafana + Cloudflare Logpush for detailed per-path latency histograms

Frequently Asked Questions

bash
#!/usr/bin/env bash
# cloudflare_timeout_diagnostics.sh
# Run this to diagnose Cloudflare API timeout issues

set -euo pipefail

ZONE_ID="YOUR_ZONE_ID"
API_TOKEN="YOUR_API_TOKEN"
ORIGIN_IP="YOUR_ORIGIN_IP"
DOMAIN="yourdomain.com"
SLOW_PATH="/api/slow-endpoint"

echo "=== 1. Check recent 524/522 errors via Cloudflare Analytics API ==="
curl -s "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/analytics/dashboard?since=-60&until=0" \
  -H "Authorization: Bearer ${API_TOKEN}" \
  -H "Content-Type: application/json" | \
  jq '.result.totals.requests.http_status | {"522": (."522" // 0), "524": (."524" // 0)}'

echo ""
echo "=== 2. Time origin directly (bypass Cloudflare proxy) ==="
curl -v --max-time 120 \
  -H "Host: ${DOMAIN}" \
  -w "\n--- Timing ---\nDNS lookup: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS handshake: %{time_appconnect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
  -o /dev/null -s \
  "http://${ORIGIN_IP}${SLOW_PATH}"

echo ""
echo "=== 3. Check if Cloudflare IPs are whitelisted on origin firewall ==="
# Fetch Cloudflare IP ranges
curl -s https://www.cloudflare.com/ips-v4 | while read -r cidr; do
  echo "Cloudflare range: ${cidr}"
done

echo ""
echo "=== 4. Inspect existing Configuration Rules (proxy timeout overrides) ==="
curl -s "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/rulesets" \
  -H "Authorization: Bearer ${API_TOKEN}" | \
  jq '.result[] | select(.phase == "http_config_settings") | {id, name, phase}'

echo ""
echo "=== 5. Create a Config Rule to extend timeout for slow path ==="
# Uncomment to apply:
# curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/rulesets/phases/http_config_settings/entrypoint" \
#   -H "Authorization: Bearer ${API_TOKEN}" \
#   -H "Content-Type: application/json" \
#   -d "{
#     \"rules\": [{
#       \"action\": \"set_config\",
#       \"action_parameters\": { \"read_timeout\": 300 },
#       \"expression\": \"http.request.uri.path contains \\\"${SLOW_PATH}\\\"\",
#       \"description\": \"Extended timeout for slow endpoint\"
#     }]
#   }"

echo ""
echo "=== 6. Python client with proper timeout + retry (print as reference) ==="
cat << 'PYTHON'
import httpx
import time

def cf_api_call_with_retry(url: str, token: str, payload: dict, max_retries: int = 4):
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }
    backoff = 1
    for attempt in range(max_retries):
        try:
            with httpx.Client(timeout=httpx.Timeout(30.0, connect=10.0)) as client:
                resp = client.post(url, json=payload, headers=headers)
            if resp.status_code == 429:
                retry_after = int(resp.headers.get("Retry-After", backoff))
                print(f"Rate limited. Waiting {retry_after}s...")
                time.sleep(retry_after)
                backoff *= 2
                continue
            resp.raise_for_status()
            return resp.json()
        except httpx.ReadTimeout:
            print(f"Timeout on attempt {attempt + 1}, retrying in {backoff}s...")
            time.sleep(backoff)
            backoff = min(backoff * 2, 60)
    raise RuntimeError(f"Failed after {max_retries} attempts")
PYTHON

echo ""
echo "=== 7. Stream live Worker logs with wrangler ==="
echo "Run: npx wrangler tail YOUR_WORKER_NAME --format=pretty"
echo "Look for: 'CPU time exceeded' or 'Script execution timed out'"

echo ""
echo "=== Diagnostics complete ==="
E

Error Medic Editorial

Error Medic Editorial is a team of senior DevOps and SRE engineers with hands-on experience operating high-traffic applications behind Cloudflare. The team specializes in networking troubleshooting, CDN configuration, and API reliability patterns.

Sources

Related Articles in Cloudflare Api

Explore More API Errors Guides