# API error codes

The stable error codes returned by the public REST API and the MCP server, with their HTTP statuses and what each one means.

Source: https://nextjs-saas-template.lubomirgeorgiev.com/docs/api/errors
Index: https://nextjs-saas-template.lubomirgeorgiev.com/llms.txt

Every failure from the public API is an RFC 9457 problem document. Its code member is stable and untranslated, so branch on the code rather than on the human-readable detail.

[Back to the API reference](https://nextjs-saas-template.lubomirgeorgiev.com/docs/api.md)

## The problem document

Responses use the application/problem+json content type and carry type, title, status, code, and detail. The type member links back to this page, anchored at the code. The detail member names the specific reason a call was refused — a full seat plan, an unknown role id — so it is what to read when deciding what to do next, while code stays the thing to branch on. When the edge supplies a ray id it is echoed as requestId, which is the value to quote in a support request, and validation failures add an errors array with one entry per rejected value.

## Codes

The HTTP status is derived from the code, so a client can rely on either. Treat an unrecognized code as a server error.

| Code                    | HTTP status | Meaning                                                                                                                                                                                                                                                                          |
| ----------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| INPUT\_PARSE\_ERROR     | 400         | The body, query, or path parameters failed schema validation. The errors array locates each rejected value and names the constraint it violated.                                                                                                                                 |
| BAD\_REQUEST            | 400         | The request was understood but is not valid in this context.                                                                                                                                                                                                                     |
| NOT\_AUTHORIZED         | 401         | No credential was presented, or it is malformed, expired, or revoked. The WWW-Authenticate header points at the resource metadata an OAuth client needs to start the connect flow.                                                                                               |
| FORBIDDEN               | 403         | The credential is valid but lacks the required scope, is a team-scoped key used outside its own team or on an account-level operation, its owner lacks the team permission this operation needs, or a plan limit such as the team's seat count blocks it. The detail says which. |
| NOT\_FOUND              | 404         | The addressed resource does not exist, or is not visible to this credential.                                                                                                                                                                                                     |
| CONFLICT                | 409         | The request conflicts with the current state of the resource.                                                                                                                                                                                                                    |
| PRECONDITION\_FAILED    | 409         | A rule of the operation was not met — a plan limit, or an invitation that was already used, for example.                                                                                                                                                                         |
| RATE\_LIMITED           | 429         | Too many requests for this credential or IP address. Authenticated credentials allow 300 requests per 60 seconds; failed authentication attempts use a separate per-IP limit. Wait the number of seconds given in retry-after.                                                   |
| INTERNAL\_SERVER\_ERROR | 500         | Something failed on the server. Details are deliberately omitted; retry, and quote requestId if it keeps happening.                                                                                                                                                              |

## Field errors

An INPUT\_PARSE\_ERROR carries an errors array with one entry per rejected value. Each entry locates the value and names what was wrong with it: in says which part of the request it came from, using the same vocabulary as an OpenAPI parameter (body, query, path, header, cookie); pointer is an RFC 6901 JSON Pointer, so /scopes/1 addresses the second element and an empty string addresses the whole payload; code is a stable, untranslated identifier from the table below; and params carries the constraint that was violated, such as {"min": 2}, when the code has one. Codes describe the shape of the failure rather than any user-facing copy, so they are safe to branch on.

| Code            | Meaning                                                                                                                                                                                                |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| required        | The value is absent. Send the member, or omit the request until you can.                                                                                                                               |
| invalid\_type   | The value is of the wrong type. params.expected names the JSON Schema type the operation documents.                                                                                                    |
| invalid\_value  | The value is the right type but not one the operation accepts — a value outside an enumeration, or one rejected by a rule specific to this operation. The OpenAPI document lists the permitted values. |
| invalid\_format | The value does not match the format the member requires. params.format names it, such as email.                                                                                                        |
| min\_length     | The string or array is shorter than allowed. params.min is the minimum.                                                                                                                                |
| max\_length     | The string or array is longer than allowed. params.max is the maximum.                                                                                                                                 |
| min\_value      | The number is below the allowed range. params.min is the minimum.                                                                                                                                      |
| max\_value      | The number is above the allowed range. params.max is the maximum.                                                                                                                                      |

## Retrying safely

429 and 5xx responses are worth retrying with backoff, honoring retry-after when it is present. Better still, pace off RateLimit-Remaining and RateLimit-Reset, which every response carries, and slow down before the limit is reached. Other 4xx codes will fail again unchanged and need a different request, a different credential, or a scope the credential does not yet hold.
