Error 520 is the proxy’s way of saying your origin answered, but the answer was not a valid HTTP response — empty, malformed, or a protocol violation. It is the vaguest error in the family precisely because it is the catch-all for everything that is not a clean failure.
That vagueness makes it frustrating, but the causes are actually a short list. Unlike a 521 (connection refused) or 522 (timeout), a 520 means the connection succeeded and something came back — so the network path is fine and the problem is at the application or protocol level. Here is how to narrow it in a few minutes.
Table of contents
- What a 520 rules out, which is most things
- Cause one: the process crashed mid-response
- Cause two: HTTP/2 negotiated but not honoured
- Cause three: headers the proxy will not accept
- Cause four: something in the middle
- How this fits the rest of the stack
- FAQ
What a 520 rules out, which is most things
Start with what the code already tells you, because it eliminates the usual suspects.
- The origin is reachable. DNS resolved, the route worked, and a TCP connection was established. Not a networking problem.
- The connection was not refused. That would be a 521. Something was listening and accepted.
- It did not time out. That would be a 522 for connection or 524 for a slow response. Something came back promptly.
- The origin produced output. It just was not a response the proxy could parse.
So the failure is in what your server sent, not whether it could be reached. That narrows the field to four causes, and they are distinguishable.
The other diagnostic asset is the Ray ID on the error page. It identifies the specific request in the proxy’s logs, and it is the thing to note before you start changing anything — support cannot help without it and neither can you, if you want to correlate against your own logs.
Cause one: the process crashed mid-response
The most common cause. Your application accepted the connection, began handling the request, and died before sending a complete response. The proxy gets a closed connection with nothing usable in it.
What kills a process mid-request:
- Out of memory. The kernel’s OOM killer terminates the process. Check
dmesgfor kill messages — this is definitive and frequently overlooked. - An unhandled exception in a worker, particularly in single-threaded runtimes where an uncaught error takes the whole worker down.
- A segfault in a native module or extension.
- A process manager restart during deploy, which produces a burst of 520s for a few seconds.
The tell is intermittency correlated with load. If 520s appear under traffic and disappear when it is quiet, this is almost certainly it, and the underlying issue is usually memory.
Look at your application’s error log and the system log at the timestamp of the Ray ID. If the process died, something recorded it — and if nothing recorded it, that itself is a finding, because it means your logging does not capture crashes.
Cause two: HTTP/2 negotiated but not honoured
This one is specific, non-obvious, and worth checking early because the fix is a single toggle.
The proxy offers HTTP/2 during the TLS handshake via ALPN. If your origin advertises support for it, the proxy uses it. If the origin then fails to actually speak HTTP/2 correctly — because a module is misconfigured, or a version has a bug, or something in front of the application downgrades — the response is malformed from the proxy’s perspective and you get a 520.
The diagnostic is straightforward: disable HTTP/2 to the origin in the proxy’s protocol settings, and see whether the 520s stop. If they do, you have found it.
The proper fix is at the origin — either configure HTTP/2 correctly or stop advertising it in ALPN. Leaving HTTP/2-to-origin disabled is an acceptable long-term state; the connection between proxy and origin is a single well-provisioned hop where HTTP/2’s multiplexing benefits are marginal.
This cause is worth ruling out early because it produces consistent 520s that look like an application problem and are not, which can waste a lot of time in the wrong logs.
Cause three: headers the proxy will not accept
The response can be structurally valid HTTP and still be rejected for being outside limits or malformed in specific ways.
- Headers too large. Very large cookies set by the origin, or a long header set by a framework, can exceed the proxy’s response header limits. Same root cause as a 431 but on the response side.
- Too many cookies. A single response setting a large number of
Set-Cookieheaders. - Invalid characters in a header. A newline or control character in a header value, which usually comes from unsanitised data being reflected into a header. This is also a response-splitting vulnerability, so it is worth fixing for two reasons.
- Empty response with a 200 status. Some applications return a bare 200 with no body and no content-length under specific error conditions.
The way to check is to bypass the proxy: request the origin address directly, with the Host header set to your domain, and read the full response headers. If the response is malformed, you will see it there.
A useful trick if you cannot reach the origin directly: temporarily set the DNS record to grey-cloud (unproxied), test, then re-enable. Remember that this exposes the origin address, so do it briefly.
Cause four: something in the middle
The remaining category is a component between the proxy and your application interfering with the response.
- Origin firewall or security software that inspects and mangles responses. Some web application firewalls and security plugins truncate or rewrite responses in ways that break them.
- Authenticated Origin Pulls enabled on the proxy without the origin configured to present or accept the expected client certificate.
- A load balancer or reverse proxy at the origin with its own buffer limits, timeouts or protocol handling, producing the malformed response before it ever leaves your infrastructure.
- A misbehaving compression layer, particularly double compression — content compressed by the application and again by the web server, producing a body that does not match its encoding header.
The isolation technique for all of these is the same: reduce the stack. Request the application directly, bypassing your own reverse proxy. If that works, the problem is in the layer you skipped. Add components back one at a time until it breaks.
A short diagnostic sequence that resolves most 520s:
- Note the Ray ID and timestamp.
- Check the origin’s error and system logs at that time for a crash or OOM kill.
- Request the origin directly with the correct Host header and read the raw response.
- Disable HTTP/2 to origin and retest.
- Bypass your own reverse proxy and request the application directly.
- Temporarily disable origin security software and retest.
If all six pass and 520s persist, that is the point at which the Ray ID and a pair of captured requests — one with the proxy, one without — are what support needs to take it further.
How this fits the rest of the stack
Diagnosing a 520 is mostly a question of whether you can see what your origin actually did at a specific moment, which is a logging and observability question more than a networking one. The RunxBuild hosting calculator covers what the stack costs across service, database, storage and bandwidth. On RunxBuild, build and runtime logs live together per deploy, services restart on failure, and rolling back to the last known-good deploy is one action — which turns the intermittent-crash case from an investigation into a decision.
Useful related references:
- Connection Closed by UNKNOWN Port 65535: Decoding SSH’s Most Cryptic Error
- The Web Server Reported a Bad Gateway Error: Fixes
- Application Server vs Web Server: The Line People Keep Blurring
- Services on RunxBuild
FAQ
What does web server is returning an unknown error mean?
It is Cloudflare error 520: the connection to your origin succeeded but the response was empty, malformed, or a protocol violation. It rules out DNS, routing, connection refusal and timeouts, so the problem is at the application or protocol level rather than the network.
What is the difference between a 520 and a 521?
A 521 means the origin refused the TCP connection outright — nothing listening, or a firewall rejecting. A 520 means the connection succeeded and the origin sent something back that could not be parsed as a valid HTTP response. Different causes and different fixes.
Can HTTP/2 cause a 520 error?
Yes, and it is a commonly missed cause. If your origin advertises HTTP/2 support via ALPN but does not handle the protocol correctly, the response is malformed from the proxy’s perspective. Disabling HTTP/2 to origin in the protocol settings is a fast way to confirm it, and is an acceptable long-term state.
Why do I get intermittent 520 errors under load?
Usually because the application process is dying mid-response — most often an out-of-memory kill. Check dmesg for OOM kill messages and the application error log at the timestamp of the Ray ID. Intermittency that correlates with traffic is the signature of this cause.
How do I debug a 520 error?
Note the Ray ID, check origin logs at that timestamp for crashes, request the origin directly with the correct Host header and read the raw response, disable HTTP/2 to origin, bypass your own reverse proxy, and temporarily disable origin security software. That sequence resolves most cases.