# 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.

Source: https://supahost.app/kb/http-status-codes · Updated 2026-11-11

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:

```json
{"code":"23505","details":"Key (email)=(sam@example.com) 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

1. Read the `code` and `message`, not just the status. `403` alone could be a grant or a policy; `42501` plus the message tells you which table.
2. Reproduce with curl to rule out client code:

   ```bash
   curl -i "https://app-one.acme.supahost.space/rest/v1/invoices?select=id,total_cents&limit=1" \
     -H "apikey: $SUPABASE_ANON_KEY"
   ```

3. Check the headers. `sb-error-code` points to Edge Functions, a JSON body with `code` to PostgREST, and an empty or plain body on a 5xx to the gateway.
4. Look up the PostgREST code in the [PostgREST error reference](https://docs.postgrest.org/en/stable/references/errors.html) and the SQLSTATE in the [Postgres error codes list](https://www.postgresql.org/docs/17/errcodes-appendix.html).

## On SupaHost

- These paths don't need an `apikey`: `/storage/v1/object/public/*`, `/functions/v1/*` and Auth's `/auth/v1/verify`, `/callback` and `/authorize` endpoints used in email links and OAuth.
- There's no `/graphql/v1` route, so GraphQL requests get the 404 `no Route matched with those values`.

## Related

- [520 and 5xx errors from the REST API](/kb/520-errors)
- ["permission denied for table" (42501) errors](/kb/permission-denied-42501)
- [PGRST106: schema not exposed](/kb/pgrst106-schema-not-exposed)
- [Edge Function returns 401](/kb/function-401)
