---
title: Errors
description: Response shape and meanings for HTTP status codes returned by the AI API.
url: https://developers.wpengine.com/docs/ai/api/errors/
image: https://developers.wpengine.com/og/docs/ai/api/errors.png
---

# Errors

The AI API returns standard HTTP status codes. Most error responses share a single JSON envelope; the exceptions are listed under [other response shapes](https://developers.wpengine.com/docs/ai/api/errors/#other-response-shapes).

## Standard error envelope

```json
{
  "error": {
    "message": "model not found: openai/does-not-exist",
    "type": "not_found_error",
    "code": 404,
    "request_id": "9f4dc8fb8841f0b0cc67612b6ef54fb7"
  }
}
```

| Field              | Type    | Notes                                                                                                                                     |
| ------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `error.message`    | string  | Human-readable description.                                                                                                               |
| `error.type`       | string  | Machine-readable category (e.g. `not_found_error`). See [status codes](https://developers.wpengine.com/docs/ai/api/errors/#status-codes). |
| `error.code`       | integer | Matches the HTTP status code.                                                                                                             |
| `error.request_id` | string  | Identifier for this request, also returned in the `X-Request-Id` response header. Quote it when you contact support.                      |

Authentication and permission failures use this envelope too — see [Authentication](https://developers.wpengine.com/docs/ai/api/authentication/#when-a-key-is-rejected) for what to do about each. The `WWW-Authenticate` header is set on `401` responses:

```http
WWW-Authenticate: Bearer realm="ai-services"
```

## Status codes

| Status | `error.type`                              | Meaning                                                                                           | Retry?                               |
| ------ | ----------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------ |
| `400`  | `invalid_request_error`                   | Invalid request body or parameters.                                                               | No — fix the request.                |
| `401`  | `authentication_error`                    | Missing, invalid, or revoked API key.                                                             | No — check the key.                  |
| `402`  | `insufficient_credits`                    | No credits remaining on the account.                                                              | No — contact support to add credits. |
| `403`  | `permission_error`                        | Valid key, but it lacks the required scope.                                                       | No — change the key’s permissions.   |
| `404`  | `not_found_error`                         | Unknown model identifier, or the resource doesn’t exist.                                          | No — fix the request.                |
| `429`  | `rate_limit_error`                        | Rate limit exceeded. See [rate limits](https://developers.wpengine.com/docs/ai/api/rate-limits/). | Yes — back off with jitter.          |
| `500`  | `internal_error`                          | Unexpected gateway error.                                                                         | Yes — retry with backoff.            |
| `502`  | `upstream_error`                          | The model provider returned an error.                                                             | Yes — retry with backoff.            |
| `503`  | `upstream_error` or `credits_unavailable` | The model provider, or the credit balance check, is temporarily unavailable.                      | Yes — retry with backoff.            |
| `504`  | `timeout_error`                           | The model provider timed out.                                                                     | Yes — retry with backoff.            |

Some operations can also return `409` or `422`; the [API reference](https://developers.wpengine.com/docs/ai/api/reference/) lists the status codes for each operation.

## Model provider errors

The gateway doesn’t pass a model provider’s error body through. It returns the standard envelope with a status based on the provider’s:

| Provider status | Gateway response                                        |
| --------------- | ------------------------------------------------------- |
| `400`           | `400` — “the upstream provider rejected the request”    |
| `404`           | `404` — “the requested model or resource was not found” |
| `429`           | `429` — “rate limited by the upstream provider”         |
| `408` or `504`  | `504` — “the upstream provider timed out”               |
| Anything else   | `502` — “upstream provider error”                       |

A provider `429` means the model is busy, not that you exceeded your own limit, but handle it the same way: back off and retry.

## Other response shapes

A few responses don’t use the standard envelope. Check the status code first and parse the body defensively.

- **`429` from the load balancer.** When you exceed a [rate limit](https://developers.wpengine.com/docs/ai/api/rate-limits/), the body is a short HTML page, not JSON.

- **Unknown path or method.** A path that doesn’t exist returns a plain-text `404 page not found`, and an unsupported method returns a plain-text `405 Method Not Allowed`.

- **`/v1/messages`.** The Anthropic-compatible endpoint returns errors in Anthropic’s format, so Anthropic SDKs can parse them. There is no `code` field; read the status from the response:

  ```json
  {
    "type": "error",
    "error": {
      "type": "not_found_error",
      "message": "model not found: anthropic/does-not-exist",
      "request_id": "fc0a809a263761c3e07ee97440121445"
    }
  }
  ```

## Streaming errors

Streaming responses (`"stream": true` on chat completions) that fail before the first byte return a normal error response. Once the stream has started, the status is already `200`, so a failure arrives inside the stream instead. If the gateway loses the model provider’s stream, it sends an error event followed by `[DONE]`:

```text
data: {"error":{"message":"stream relay error","type":"server_error"}}


data: [DONE]
```

This frame doesn’t follow the standard envelope: its `type` is `server_error`, and it carries no `code` or `request_id`.

Treat a chunk with an `error` field as a failed response, even though `[DONE]` follows it. If the connection closes without `data: [DONE]`, the stream was cut off. Both are recoverable failures — retry the request. [Stream a chat completion](https://developers.wpengine.com/docs/ai/api/stream-chat-completions/) shows code that handles both.

If the client disconnects mid-stream, the gateway stops relaying and records the usage consumed up to that point.

---

> #### Handling failure
>
> - [Authentication — what a 401 and a 403 each mean for your key](https://developers.wpengine.com/docs/ai/api/authentication/#when-a-key-is-rejected)
> - [Rate limits — quotas, the 429 response, and backoff](https://developers.wpengine.com/docs/ai/api/rate-limits/)
> - [API reference — per-operation status codes](https://developers.wpengine.com/docs/ai/api/reference/)

## Was this helpful?

Thanks for the feedback!

```json
{"@context":"https://schema.org","@graph":[{"@type":"WebSite","@id":"https://developers.wpengine.com/#website","name":"WP Engine Product Documentation","url":"https://developers.wpengine.com/","description":"Resources for developing, deploying, and scaling on WP Engine.","inLanguage":"en-US","keywords":["API documentation","product documentation","headless WordPress","managed WordPress hosting"],"publisher":{"@id":"https://wpengine.com/#organization"}}]}
```
