# Error codes

> Status: Available. Errors use PostgreSQL SQLSTATE codes on both protocols. Four of them need handling in every client.

Over HTTP the same code is in the JSON body under `error`.

## The four you must handle

| Code | Meaning | What to do |
|---|---|---|
| `40001` | Serialization conflict or ownership change | Retry the whole transaction. Locking is no-wait, so this is normal under contention |
| `40003` | Commit outcome unknown | **Do not retry yet.** [Look the transaction up first](https://gauntlet-db.stavros.xyz/docs/concepts/transactions.md#40003-the-commit-outcome-is-unknown) |
| `57P03` | Cannot serve right now | Retry with backoff. Inside a transaction: `ROLLBACK`, then retry the whole transaction |
| `53300` | Too many connections | Back off or use another node. Keep your pool below the node's limit |

### 57P03 in detail

You can see `57P03` when connecting (the node is overloaded, the database could not be activated, or startup took too long), when a node is shutting down, under memory pressure, or when the bucket or a shard owner is unavailable. It is always retryable. Over HTTP it is status 503.

### 53300 in detail

Each node accepts **128 PostgreSQL connections** by default; the operator can change that with `max-connections` (1 to 10000). The count includes connections that are starting up and connections that are idle. One connection past the limit gets `FATAL: sorry, too many clients already`. The limit is per node, so other nodes may have room.

## Other codes

| Code | Meaning |
|---|---|
| `23505` / `23502` | UNIQUE / NOT NULL violation |
| `42P01` / `42703` / `42702` | Unknown table / unknown column / ambiguous column |
| `42P07` / `42P16` | Table already exists / invalid table definition |
| `42601` / `42000` | Syntax error / other planning error |
| `42883` / `42803` | Unknown function or wrong argument count / aggregate used where it is not allowed |
| `0A000` | Feature not supported |
| `25001` | `CREATE TABLE` inside a transaction or mixed with other statements |
| `25006` | Write in a read-only transaction |
| `25P02` | The transaction is aborted; send `ROLLBACK` |
| `25P01` | No transaction is open |
| `54000` | A size limit was exceeded (transaction, value, result, SQL text) |
| `57014` | The statement hit its limit: 20 s or 500 million engine instructions |
| `22003` | Integer or numeric overflow |
| `28P01` | Wrong password (database token) |
| `28000` | Plaintext connection when TLS is required |
| `3D000` | Database does not exist, or was dropped |
| `08P01` | Malformed protocol message or missing parameter |
| `53200` / `53100` | The engine could not allocate memory / storage full |
| `XX000` / `XX001` | Internal error / invalid stored data. Never retried automatically; report it |

## HTTP status mapping

| SQLSTATE | HTTP status |
|---|---|
| `40001` | 409 |
| `57P03` | 503 |
| `40003` | 504 |
| `XX…` | 500 |
| Every other SQL error | 400 |

---
Source: https://gauntlet-db.stavros.xyz/docs/sql/errors
