Files
supabase/apps/docs/content/guides/api/rest/postgrest-error-codes.mdx
T
5a676e2a86 docs: split Studio logs from ClickHouse log queries (#49501)
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## Stack

Draft stack extracted from `docs/monitoring`. Merge bottom-up.
Troubleshooting / debugging-guide rewrite is out of scope.

1. #49503 move inspect and advisors
2. **#49501** split Studio logs from ClickHouse queries ← **this PR**
3. #49500 treat reports as signal dashboards
4. #49502 add Observe the data hub
5. #49506 add agent setup components
6. #49504 add hire-an-agent templates
7. #49505 restructure observability nav and overview

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Docs update. Second layer in the observability stack.

## What is the current behavior?

`/guides/monitoring-and-debugging/logs` mixes the Studio Logs UI with
ClickHouse query syntax, sources, and recording extra events.

## What is the new behavior?

- Logs is the Studio interface guide (filters, log types, inspecting a
row)
- Query and filter logs (`advanced-log-filtering`) owns ClickHouse SQL,
sources, MCP/API/CLI access, and recording extra Postgres/API/Realtime
events
- Log field reference explains `log_attributes` query paths
- Nav labels and cross-links follow the new titles

## Additional context

Forward links to the later Observe the data hub are added in #49502.

## Self-review

- Existing `#querying-with-the-logs-explorer` and
`#configuring-pgauditlog` anchors now live on Query and filter logs
- Debugging-guide links that pointed at the old Logs Explorer heading
were retargeted so they still resolve
<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a
href="https://cursor.com/agents/bc-a3cb5ece-925b-4046-b58a-5d69e9a9d794?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-a3cb5ece-925b-4046-b58a-5d69e9a9d794&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Saxon Fletcher <SaxonF@users.noreply.github.com>
Co-authored-by: Nik Richers <nik@validmind.ai>
2026-09-04 13:38:36 +10:00

236 lines
15 KiB
Plaintext

---
id: 'postgrest-error-codes'
title: 'Error Codes'
description: 'PostgREST Error Codes'
subtitle: 'Identify PostgREST errors and resolve them'
sidebar_label: 'Debugging'
---
<Admonition type="note">
The docs reflect the error codes and information in [PostgREST's official
docs](https://docs.postgrest.org/en/stable/).
</Admonition>
## 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 | |
## 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 [SQL Editor](/dashboard/project/_/sql/new?skip=true&source=logs) with the query source set to **Logs**. 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;
```
<Admonition type="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.
</Admonition>
### 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;
```