HTTP status codes from the Supabase APIs
A reference of the HTTP status codes the SupaHost gateway, the Data API (PostgREST), Storage and Edge Functions return, what each one means and where to look first.
The status code tells you which layer answered. On SupaHost a request passes through the gateway first, then reaches the service for its path: /rest/v1 (PostgREST), /auth/v1, /storage/v1 or /functions/v1. Errors from PostgREST have a JSON body with a code; errors from the gateway don't.
What you see
A typical Data API error body:
{"code":"23505","details":"Key (email)=([email protected]) already exists.","hint":null,"message":"duplicate key value violates unique constraint \"customers_email_key\""}
code is either a Postgres SQLSTATE (five characters, like 23505) or a PostgREST code (PGRST plus three digits). supabase-js puts the same fields on error.
Why it happens
The table below lists the codes you're most likely to meet and their usual cause.
| Status | Where it comes from | Usual cause |
|---|---|---|
| 200 / 201 / 204 | PostgREST | Success. 201 after an insert, 204 when nothing is returned |
| 206 | PostgREST | Partial content: you asked for a range of rows |
| 300 | PostgREST PGRST201, PGRST203 |
Ambiguous embed or overloaded function: name the relationship or rename the function |
| 400 | PostgREST PGRST100, Postgres P0001, 22P02 |
Bad filter syntax, a raise exception in your function, invalid input such as a bad UUID |
| 401 | SupaHost gateway | No API key found in request: send the apikey header |
| 401 | PostgREST PGRST301, PGRST303 |
Token invalid, expired or issued in the future |
| 401 / 403 | Postgres 42501 |
Missing grant or RLS rejected a write. 401 when the caller is anon, 403 when signed in |
| 404 | SupaHost gateway | no Route matched with those values: the path isn't one the gateway serves |
| 404 | PostgREST PGRST205, PGRST202 |
Table or function not in the schema cache |
| 405 | PostgREST, Postgres 25006 |
Wrong HTTP method for the endpoint, or a write inside a read-only transaction |
| 406 | PostgREST PGRST116, PGRST106 |
.single() got zero or several rows; schema not exposed |
| 409 | Postgres 23505, 23503 |
Unique or foreign key violation |
| 413 | Storage | File bigger than the upload limit |
| 416 | PostgREST PGRST103 |
Range or offset past the end of the results |
| 429 | Auth | Rate limit hit, for example too many emails |
| 500 | PostgREST, Postgres | Error inside a function or view, statement timeout (57014), infinite recursion in a policy (42P17) |
| 502 | SupaHost gateway | The project's service didn't answer, for example while it restarts |
| 503 | PostgREST PGRST000-PGRST002 |
Can't reach Postgres or load the schema cache |
| 504 | PostgREST PGRST003 |
Waited too long for a free connection in the Data API's pool |
Edge Functions add their own codes, each with an sb-error-code header: 401 UNAUTHORIZED_NO_AUTH_HEADER / UNAUTHORIZED_INVALID_JWT, 404 NOT_FOUND, 500 WORKER_ERROR, 503 BOOT_ERROR, 504 IDLE_TIMEOUT and 546 WORKER_RESOURCE_LIMIT.
How to fix it
Read the
codeandmessage, not just the status.403alone could be a grant or a policy;42501plus the message tells you which table.Reproduce with curl to rule out client code:
curl -i "https://app-one.acme.supahost.space/rest/v1/invoices?select=id,total_cents&limit=1" \ -H "apikey: $SUPABASE_ANON_KEY"Check the headers.
sb-error-codepoints to Edge Functions, a JSON body withcodeto PostgREST, and an empty or plain body on a 5xx to the gateway.Look up the PostgREST code in the PostgREST error reference and the SQLSTATE in the Postgres error codes list.
On SupaHost
- These paths don't need an
apikey:/storage/v1/object/public/*,/functions/v1/*and Auth's/auth/v1/verify,/callbackand/authorizeendpoints used in email links and OAuth. - There's no
/graphql/v1route, so GraphQL requests get the 404no Route matched with those values.