# Error Codes

Identify PostgREST errors and resolve them

PostgREST Error Codes

Note: The docs reflect the error codes and information in [PostgREST's official
docs](https://docs.postgrest.org/en/stable/).

## PostgREST error codes

Error codes from the Data API are returned as JSON objects

```json
{
  "code": "42703",
  "details": null,
  "hint": "Perhaps you meant to reference the column some_table.fake_col",
  "message": "column some_table.fake_col does not exist"
}
```

Here is the full list of error codes and their descriptions:

## Database level errors

To understand the errors reference the [Postgres Error Docs](https://www.postgresql.org/docs/current/errcodes-appendix.html).

Here's the text formatted as a proper markdown table:

| Postgres error code(s) | HTTP status                    | Error description               |
| ---------------------- | ------------------------------ | ------------------------------- |
| 08\*                   | 503                            | connection error                |
| 09\*                   | 500                            | triggered action exception      |
| 0L\*                   | 403                            | invalid grantor                 |
| 0P\*                   | 403                            | invalid role specification      |
| 23503                  | 409                            | foreign key violation           |
| 23505                  | 409                            | uniqueness violation            |
| 25006                  | 405                            | read only SQL transaction       |
| 25\*                   | 500                            | invalid transaction state       |
| 28\*                   | 403                            | invalid auth specification      |
| 2D\*                   | 500                            | invalid transaction termination |
| 38\*                   | 500                            | external routine exception      |
| 39\*                   | 500                            | external routine invocation     |
| 3B\*                   | 500                            | savepoint exception             |
| 40\*                   | 500                            | transaction rollback            |
| 53400                  | 500                            | config limit exceeded           |
| 53\*                   | 503                            | insufficient resources          |
| 54\*                   | 500                            | too complex                     |
| 55\*                   | 500                            | obj not in prerequisite state   |
| 57\*                   | 500                            | operator intervention           |
| 58\*                   | 500                            | system error                    |
| F0\*                   | 500                            | config file error               |
| HV\*                   | 500                            | foreign data wrapper error      |
| P0001                  | 400                            | default code for "raise"        |
| P0\*                   | 500                            | PL/pgSQL error                  |
| XX\*                   | 500                            | internal error                  |
| 42883                  | 404                            | undefined function              |
| 42P01                  | 404                            | undefined table                 |
| 42P17                  | 500                            | infinite recursion              |
| 42501                  | if authenticated 403, else 401 | insufficient privileges         |
| other                  | 400                            |                                 |

Note: Some codes in this table are triggered by platform conditions rather than application code. Seeing them in high volume usually points to an infrastructure event rather than a bug in your queries:

- **25006** — The database has entered read-only mode due to disk quota. See [Read-only mode](/docs/guides/platform/database-size#read-only-mode) for causes and recovery steps.
- **53100** — Disk is full. Supabase emits this alongside 25006 during severe disk exhaustion.
- **53300** — Too many connections. The connection pool has reached its limit; check your [connection pool settings](/docs/guides/database/connection-management).
- **57P03** — The database cannot accept connections, typically during a restart or failover.

When you see these codes in volume, check the [Database dashboard](/dashboard/project/_/observability/database) before debugging application code.

## API level errors

### Connection errors

Errors that prevent that data API from interacting with Postgres.

| Code     | HTTP status | Description                                                                                                           |
| -------- | ----------- | --------------------------------------------------------------------------------------------------------------------- |
| PGRST000 | 503         | Could not connect with the database due to an incorrect connection string or due to the Postgres service not running. |
| PGRST001 | 503         | Could not connect with the database due to an internal error.                                                         |
| PGRST002 | 503         | Could not connect with the database when building the schema cache                                                    |
| PGRST003 | 504         | The request timed out waiting for a connection from PostgREST's internal pool                                         |

### API requests

Errors with data structures or request formatting

| Code     | HTTP status | Description                                                                                                                 |
| -------- | ----------- | --------------------------------------------------------------------------------------------------------------------------- |
| PGRST100 | 400         | Parsing error in the query string parameter.                                                                                |
| PGRST101 | 405         | For database functions, only `GET` and `POST` verbs are allowed. Any other verb will throw this error.                      |
| PGRST102 | 400         | An invalid request body was sent(e.g. an empty body or malformed JSON).                                                     |
| PGRST103 | 416         | An invalid range was specified for limits.                                                                                  |
| PGRST105 | 405         | An invalid `UPDATE`/`UPSERT` request was done                                                                               |
| PGRST106 | 406         | The schema specified when switching schemas is not exposed to the API.                                                      |
| PGRST107 | 415         | The `Content-Type` sent in the request is invalid.                                                                          |
| PGRST108 | 400         | The filter is applied to an embedded resource that is not specified in the `select` part of the query string.               |
| PGRST111 | 500         | An invalid `response.headers` was set.                                                                                      |
| PGRST112 | 500         | The status code must be a positive integer.                                                                                 |
| PGRST114 | 400         | For an `UPSERT` using `PUT` when limits and offsets are used.                                                               |
| PGRST115 | 400         | For an `UPSERT` using `PUT` when the primary key in the query string and the body are different.                            |
| PGRST116 | 406         | More than 1 or no items where returned when requesting a singular response.                                                 |
| PGRST117 | 405         | The HTTP verb used in the request in not supported.                                                                         |
| PGRST118 | 400         | Could not order the result using the related table because there is no many-to-one or one-to-one relationship between them. |
| PGRST120 | 400         | An embedded resource can only be filtered using the `is.null` or `not.is.null` operators.                                   |
| PGRST121 | 500         | API can't parse the JSON objects in RAISE `PGRST` error.                                                                    |
| PGRST122 | 400         | Invalid preferences found in `Prefer` header with `Prefer: handling=strict`.                                                |
| PGRST123 | 400         | Aggregate functions are disabled.                                                                                           |
| PGRST124 | 400         | `max-affected` preference is violated.                                                                                      |
| PGRST125 | 404         | Invalid path is specified in request URL.                                                                                   |
| PGRST126 | 404         | Open API config is disabled but API root path is accessed.                                                                  |
| PGRST127 | 400         | The feature specified in the `details` field is not implemented.                                                            |
| PGRST128 | 400         | `max-affected` preference is violated with `RPC` call.                                                                      |

### Schema cache errors

The API is unable to identify relationships or objects within the query requests.

| Code     | HTTP status | Description                                                                                                                                                                                                                                                                             |
| -------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| PGRST200 | 400         | Caused by stale foreign key relationships, otherwise any of the embedding resources or the relationship itself may not exist in the database.                                                                                                                                           |
| PGRST201 | 300         | An ambiguous embedding request was made.                                                                                                                                                                                                                                                |
| PGRST202 | 404         | Caused by a stale function signature, otherwise the function may not exist in the database.                                                                                                                                                                                             |
| PGRST203 | 300         | Caused by requesting overloaded functions with the same argument names but different types, or by using a `POST` verb to request overloaded functions with a `JSON` or `JSONB` type unnamed parameter. The solution is to rename the function or add/modify the names of the arguments. |
| PGRST204 | 400         | Caused when the column specified in the columns query parameter is not found.                                                                                                                                                                                                           |
| PGRST205 | 404         | Caused when the table specified in the URI is not found.                                                                                                                                                                                                                                |

### Authentication errors

The request lacks the proper credentials to request data

| Code     | HTTP status | Description                                                                                      |
| -------- | ----------- | ------------------------------------------------------------------------------------------------ |
| PGRST300 | 500         | PostgREST does not have an active JWT secret to validate requests                                |
| PGRST301 | 401         | Provided JWT couldn't be decoded or it is invalid.                                               |
| PGRST302 | 401         | Attempted to do a request without the header `Auth: Bearer` when the anonymous role is disabled. |
| PGRST303 | 401         | JWT claims validation or parsing failed.                                                         |

### Internal errors

Data API error unspecified

| Code     | HTTP status | Description                                                                 |
| -------- | ----------- | --------------------------------------------------------------------------- |
| PGRSTX00 | 500         | Internal errors related to the library used for connecting to the database. |

## Viewing errors in the logs

One can filter for API errors in the [Explorer](/dashboard/project/_/explorer) after selecting **Run SQL**, query source **Logs**, and a time range. Below are useful queries for filtering and analyzing API errors:

### Find all API errors that occurred at the database level

```sql
select
  timestamp,
  event_message,
  log_attributes['parsed.error_severity'] as error_severity,
  log_attributes['parsed.user_name'] as user_name,
  log_attributes['parsed.query'] as query,
  log_attributes['parsed.detail'] as detail,
  log_attributes['parsed.hint'] as hint,
  log_attributes['parsed.sql_state_code'] as sql_state_code,
  log_attributes['parsed.backend_type'] as backend_type
from logs
where
  source = 'postgres_logs'
  and log_attributes['parsed.error_severity'] in ('ERROR', 'FATAL', 'PANIC')
  and log_attributes['parsed.user_name'] = 'authenticator' -- the authenticator role represents the database API
order by timestamp desc
limit 100;
```

### Find specific database error from the data API

```sql
select
  timestamp,
  event_message,
  log_attributes['parsed.error_severity'] as error_severity,
  log_attributes['parsed.user_name'] as user_name,
  log_attributes['parsed.query'] as query,
  log_attributes['parsed.detail'] as detail,
  log_attributes['parsed.hint'] as hint,
  log_attributes['parsed.sql_state_code'] as sql_state_code,
  log_attributes['parsed.backend_type'] as backend_type
from logs
where
  source = 'postgres_logs'
  and log_attributes['parsed.sql_state_code'] = '42501'
  and log_attributes['parsed.user_name'] = 'authenticator' -- the authenticator role represents the database API
order by timestamp desc
limit 100;
```

Note: The codes in the table above are returned in the response body, not recorded in the logs. Use the queries below to find the failing requests, then read the `code` from the response your client received.

### Find API errors at the gateway

`sb_error_code` is the error code the API gateway recorded for a request, such as `UNAUTHORIZED_MISSING_API_KEY`. It is empty when the request reached PostgREST and failed there.

```sql
select
  timestamp,
  log_attributes['response.status_code'] as status_code,
  log_attributes['response.headers.sb_error_code'] as gateway_error_code,
  log_attributes['request.path'] as path,
  event_message
from logs
where
  source = 'edge_logs'
  and toInt32OrZero(log_attributes['response.status_code']) >= 300
  and match(log_attributes['request.path'], '^/rest/v1/')
order by timestamp desc
limit 100;
```

### Count errors per path by hour:

```sql
select
  toStartOfHour(timestamp) as hour,
  count() as error_count,
  log_attributes['request.path'] as path
from logs
where
  source = 'edge_logs'
  and toInt32OrZero(log_attributes['response.status_code']) >= 300
  and match(log_attributes['request.path'], '^/rest/v1/')
group by hour, path
order by hour desc
limit 100;
```
