520 and 5xx errors from the REST API
What 500, 502, 503, 504 and Cloudflare 520 errors from the Data API mean on SupaHost, how to tell a database error from a gateway error, and what to check for each.
A 5xx response means the server side failed, but which part failed matters. On SupaHost, a request goes from the gateway on your instance to the project's PostgREST, then to Postgres. Each layer fails differently.
What you see
One of:
500with a JSON body that has acode, like{"code":"57014","message":"canceling statement due to statement timeout",...}502with an empty or plain-text body503with{"code":"PGRST002",...}or anotherPGRST00xcode504with{"code":"PGRST003","message":"Timed out acquiring connection from connection pool.",...}520with a Cloudflare error page
Why it happens
520 is a Cloudflare code, not a SupaHost one. Cloudflare returns it when the server behind it sends something Cloudflare can't use. SupaHost doesn't put Cloudflare in front of your project API, so a 520 means there's a Cloudflare proxy somewhere in your own request path: your app's domain proxied by Cloudflare, a Cloudflare Worker forwarding to SupaHost, or a custom domain set to "Proxied". Look at the response headers: Cloudflare adds cf-ray.
The other codes come from SupaHost's stack:
| Code | Body | Meaning |
|---|---|---|
| 500 | JSON with code |
Postgres raised an error: a bug in a function or view, a statement timeout (57014), a recursive policy (42P17) |
| 502 | Empty or plain text | The gateway couldn't reach the project's service. It's restarting, stopped or overloaded |
| 503 | JSON, PGRST000-PGRST002 |
PostgREST is up but can't reach Postgres or load its schema cache |
| 504 | JSON, PGRST003 |
The Data API's connection pool stayed full for too long |
How to fix it
Check where the response came from. A
cf-rayheader means Cloudflare. A JSON body withcodemeans PostgREST or Postgres. An empty 502 means the gateway.For a 520, call the project API directly to compare:
curl -i "https://app-one.acme.supahost.space/rest/v1/bookings?select=id&limit=1" \ -H "apikey: $SUPABASE_ANON_KEY"If that works, fix the proxy: for a custom domain on SupaHost the Cloudflare record must be "DNS only". See custom domain behind Cloudflare proxy.
For a 500, read the
codeandmessage. Reproduce the query in Studio's SQL editor, then fix the function, view or policy. For timeouts, see statement timeout.For a 502, wait a minute and retry. If it keeps happening, check that the instance answers at
https://acme.supahost.space(it returns{"instance":"acme","status":"ok"}) and look for a health alert email.For 503 and 504, look for long-running queries and connection use:
select state, count(*), max(now() - query_start) as longest from pg_stat_activity where datname = current_database() group by state;Slow queries hold the Data API's few pool connections (5 per project), so new requests queue and then fail with 504. Speed up the slow queries or cancel the stuck ones.
Retry safely. Add retries with backoff for 502, 503 and 504 on reads. Only retry writes when they're idempotent, such as an upsert on a unique key.
On SupaHost
Planned events that can cause short bursts of 502 or 503:
- Changing plan resizes the VM: a minute or two of downtime for every project on the instance.
- Software upgrades replace the stack's services. Automatic upgrades run in the maintenance window you choose, 03:00-05:00 UTC; "Upgrade now" on the Instance page runs one straight away.
- Restoring a project stops that project's Auth, REST and Storage while the database is swapped. Other projects keep running.
The dashboard has no searchable log explorer. On Business, sudo supahost-logs app-one rest shows recent PostgREST output and sudo supahost-logs app-one http the gateway's request log for the project.