524
Cloudflare's own code for a request that got all the way in and then went quiet: the connection succeeded, the origin received it, and 125 seconds later there was still no HTTP response to send back.
The same three digits are three different problems depending on which side of the request you are on. Read the block that describes you.
Why you are seeing it
The request hangs for over two minutes and then resolves into Cloudflare's HTML error page. Two minutes is longer than any user waits and longer than several mobile networks keep an idle connection alive, so in practice the failure often reaches you as an abort or a network error rather than as a status code at all — which sends the investigation toward your own code instead of toward the origin. It is one endpoint, always a slow one: an export, a report, a bulk import, a search with no bounds, or an upload that is processed synchronously.
What to do
Give every request a deadline you chose, well under 125 seconds, using an `AbortController` and a timer, so the user sees your message rather than an unstyled page from an infrastructure provider — and so the elapsed time gets logged. Then change the shape of anything that legitimately runs long, which is Cloudflare's own recommendation: have the endpoint return a job identifier immediately and poll for the result, because no timeout configuration will make a two-minute request survive every proxy, load balancer and mobile network between you and the server. Never retry a 524 automatically. The origin very probably finished the work seconds after Cloudflare walked away, so a retried import runs twice; if the operation must be retryable, send an idempotency key and let the server recognise the repeat.
Why you are seeing it
Your origin accepted the connection and read the request, which means the entire class of connectivity problems is already excluded — ports, bind addresses, firewalls and Cloudflare IP ranges are all fine, or you would have a 521, 522 or 523 instead. The request is either still running or has never started. Those two are the causes Cloudflare names, a long-running process and an overloaded server, and they need opposite fixes: one is a slow query, a lock or an unbounded loop over a growing table, and the other is a saturated worker pool where the request is queued behind others and the application has not touched it yet.
What to do
Your own access log tells you which, and it is the first thing to read. If the request appears with a duration above 125 seconds, the origin finished after Cloudflare gave up — the work is genuinely slow, the log holds the real duration, and the problem is inside that request. If the request never appears at all, nothing was slow: it sat in a queue in front of the application, which is a capacity problem, and profiling the endpoint will find nothing. From there, Cloudflare's documented options are what you actually have. Move long-running work off the request path and poll for its result. Put anything that must exceed 125 seconds behind a DNS-only subdomain, since the timeout only exists on proxied traffic. Watch Origin Analytics for response times approaching the threshold rather than waiting for them to cross it. Raising the timeout is available only on Enterprise zones, via Cache Rules or the zone-setting API, and only up to 6,000 seconds — so for most people the number is fixed and the design has to change instead. Set your own application timeout below 125 seconds too, so the request is killed by something that can log why.
Why you are seeing it
The site is running and it received what you asked for — it just took so long to answer that the service in front of it stopped waiting and showed you this page instead. It is usually something heavy: a large export, a big upload, a search over a lot of data, or a site that is busier than usual. Everything else on the same site will often work perfectly, which is why the failure looks arbitrary from the outside.
What to do
If you asked for something large, ask for less: a shorter date range, a smaller file, fewer items at a time. That single change fixes more 524s than any amount of reloading, because the timeout is about duration and duration follows size. Before repeating an upload or a submission, check whether it actually went through — the timeout hid the answer, but the work very likely finished a moment later, so the file may already be there and doing it again may create a duplicate. Look at the relevant list, folder or order history first. Reloading immediately is the one thing to avoid when the site is busy, since each reload asks the same overloaded server to do the same slow job again.
Run this against the URL that failed. It prints the status without the error page, so you can see what the server said rather than what the browser rendered.
curl -sS -o /dev/null -D - --max-time 300 -w '\n%{http_code} connect=%{time_connect}s ttfb=%{time_starttransfer}s total=%{time_total}s\n' https://example.com/slow-report`--max-time 300` is curl's limit on the whole operation and it must be well above 125 seconds, or curl gives up first and you measure your own patience instead of Cloudflare's. The shape of a 524 in that output is unmistakable: `connect` is a fraction of a second, `ttfb` and `total` are both around 125, and the status is 524 — a fast connection followed by a very long silence, which is exactly the pattern that separates it from 522, where the connection itself never completed. Then take the edge out of the path with `--resolve example.com:443:203.0.113.10`, pointing at your origin address, and run the same request again. If the origin answers after 200 seconds, the work really is that slow and the 524 was an accurate report; the number curl prints is how long the request actually needs, which is the figure to design around. If the origin answers quickly with the edge bypassed, the extra time is being added in front of the application — a Worker, a WAF rule, or HTTP/2 to the origin — and the origin is not the place to look. While the command runs, watch the origin's own access log: a request that appears there with a duration above 125 seconds proves the work completed after Cloudflare stopped listening, which is precisely why retrying a write after a 524 is unsafe. A request that never appears in that log at all means it was queued, never started, and the endpoint is not slow — the server is full.
524 is not an IETF status code — the registered 5xx range ends at 511, and 520-526 belong to Cloudflare, are documented only by Cloudflare, and appear only on traffic that is actually proxied. Cloudflare's definition is unusually precise and worth reading twice: error 524 indicates that Cloudflare successfully connected to the origin web server, but the origin did not provide an HTTP response before the default 125 seconds. The first clause is the diagnosis. A successful connection means the origin was listening, on a port Cloudflare proxies, and the firewall let Cloudflare through — every question a 521, 522 or 523 would raise is already answered, and none of them are worth checking. What remains is inside the application. The 125 seconds is Cloudflare's Proxy Read Timeout, listed at that value in its connection-limits reference; it is configurable only on Enterprise zones, where Cache Rules or the zone-setting API can raise it as far as 6,000 seconds, so on every other plan the number is a fact of the environment rather than a setting to adjust. Cloudflare lists two causes — a long-running process on the origin web server, and an overloaded origin web server — and those are genuinely different problems that look identical from the edge: in the first the request is executing and simply takes longer than the timeout, and in the second it has not started because the worker pool is full. Cloudflare's documented resolutions split the same way: take the slow process up with the hosting provider, implement status polling for lengthy HTTP operations rather than holding a request open, move anything that legitimately exceeds 125 seconds behind a subdomain that is DNS-only (grey-clouded) so it does not pass through the proxy at all, and use Origin Analytics to watch response times climbing toward the threshold before they cross it. One property carries over from RFC 9110 §15.6.5's ordinary 504 and matters more here because the timer is so long: the origin was still working when Cloudflare stopped listening, so a 524 is not evidence that nothing happened.
| Confused with | How to tell them apart |
|---|---|
| 504 | 504 is the IETF code from RFC 9110 §15.6.5 for a gateway that received no timely response, and any proxy may return it. 524 is Cloudflare's, and it means Cloudflare's own 125-second Proxy Read Timeout fired. So a 504 that arrives through Cloudflare was produced by something behind Cloudflare and relayed, which puts the timer in your own stack rather than in theirs — and the elapsed time will name it, typically 60 seconds for nginx or an Application Load Balancer. |
522 | Both are timeouts and they measure different phases. 522 is connection-level: Cloudflare defines it as no SYN+ACK within 19 seconds of its SYN, or no acknowledgement of its request within 90 seconds once the connection is established. 524 is response-level, and only happens after all of that succeeded. Getting 524 therefore proves the network path, the port and the firewall are all working, which is real information rather than a consolation. |
| 521 | 521 is a refusal and 524 is a silence, and they exclude each other completely. Cloudflare defines 521 as the origin refusing its connection, which points at a stopped process, a wrong bind address, a port outside Cloudflare's proxied list, or a firewall rejecting Cloudflare's ranges. A 524 has already ruled every one of those out by connecting successfully, so any time spent on ports and firewalls after seeing a 524 is time spent on the wrong problem. |
520 | 520 is the origin answering with something Cloudflare cannot use — empty, unknown or unexpected, including headers over its 128 KB limit — while 524 is the origin not answering in time at all. The distinction is worth keeping straight because the fixes share nothing: 520 sends you to what your application emits, including malformed headers and a misconfigured HTTP/2 to origin, and 524 sends you to how long it takes. |
Cloudflare Tunnel | A tunnelled origin changes where to look but not the timer. The 125-second Proxy Read Timeout is a property of the proxied path, so a request served through a tunnel hits the same limit, and the connector's own logs become the middle layer between the edge and the application. Check them alongside the origin's access log: a request present in the connector's log but absent from the application's was queued behind the application, not slowed by it. |
All of these run in your browser — nothing is uploaded.
Codes people usually end up reading in the same session as 524.
Read the response headers rather than the page. curl -sS -o /dev/null -D - https://example.com/path prints them without the body, and server, via and cf-ray between them name the layer that answered. A cf-ray value means Cloudflare handled the response and is the id their support will ask for. To take the edge out of the picture entirely, repeat the request with --resolve example.com:443:203.0.113.10, which connects to the origin address you name while still sending the original host name and SNI — if the answer changes, the edge and the origin disagree.
No, and you should never branch on it. RFC 9112 tells clients to ignore the reason phrase, servers are free to change it, and HTTP/2 and HTTP/3 do not carry one at all — so 404 Not Found over HTTP/1.1 arrives as a bare 404 over HTTP/2. The phrases on this site are the registered ones because they are what people search for and what appears in an HTTP/1.1 log, not because any software depends on them.
Retry 5xx and 429; do not retry 4xx, because nothing about the request will be different next time. If the response carries Retry-After, honour it — RFC 9110 defines it for exactly this, and it may be either a number of seconds or a date. Otherwise use exponential backoff with jitter and a hard cap, and only for idempotent methods: a retried POST can charge a card twice. A retry storm against a server that is already failing is how a brief incident becomes a long one.
Yes, and the only rule that matters is that the code has to be true. Anything that reads your responses automatically — search engines, monitoring, caches, client retry logic — makes decisions from the number and never from the page. Serving an error page with 200 hides the failure from your own alerting; serving 200 for a missing page gets the error indexed as content; returning 500 for a request that was simply malformed sends whoever is on call to the wrong half of the stack.
Still stuck on 524? browse every status code in the reference — or go back up to the block written for your side of the stack.