> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runtype.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runtype.com/_mcp/server.

# API error reference

This page lists the error response formats, status codes, and error codes that the Runtype API returns. For steps that fix each error, see [Common errors and solutions](/user-guide/troubleshooting-faq/common-errors-and-solutions) and [Rate limits and usage](/user-guide/troubleshooting-faq/rate-limits-and-usage).

## Error response body

An error response is a JSON object with an `error` string. Most responses add more fields. The following table lists the fields that can appear:

| Field        | Type   | Description                                                                                              |
| ------------ | ------ | -------------------------------------------------------------------------------------------------------- |
| `error`      | string | A short description of the error. Present on every error response.                                       |
| `message`    | string | A longer, human-readable explanation.                                                                    |
| `code`       | string | A stable, machine-readable error code. Branch on `code`, not on the `error` or `message` text.           |
| `details`    | array  | Field-level problems in a request that failed validation.                                                |
| `limitType`  | string | The kind of limit that refused the request. Present on burst-rate, spend-cap, and Test key limit errors. |
| `resetsAt`   | string | An ISO 8601 timestamp. Present on `RATE_LIMIT_EXCEEDED` and `SPEND_LIMIT_EXCEEDED` responses.            |
| `upgradeUrl` | string | The dashboard path where you can change the setting that caused the error, such as `/settings/billing`.  |
| `stats`      | object | Usage figures for the limit that refused the request.                                                    |

The following example shows a `404` response for a path that doesn't exist:

**`404 response`**

```json title="404 response"
{
  "error": "Not Found",
  "message": "The requested resource was not found",
  "timestamp": "2026-09-27T14:03:11.482Z"
}
```

A request for a specific resource that doesn't exist, such as an unknown Flow ID, also returns `404`. Its `error` string names the resource.

Every API response includes an `X-Runtype-Request-ID` header. Include its value when you contact support about an error.

## Validation errors

When a request body, query parameter, or path parameter fails schema validation, the API returns `400` before it runs the request. The `details` array has one entry for each problem:

**`400 response`**

```json title="400 response"
{
  "error": "Validation error",
  "details": [
    {
      "code": "MISSING_REQUIRED_FIELD",
      "message": "Invalid input: expected string, received undefined",
      "path": "name"
    }
  ]
}
```

Each entry has these fields:

* `code`: the detail code.
* `message`: a description of the problem.
* `path`: the dotted path to the field, such as `steps.0.config`. The path is an empty string for the request root.
* `suggestion`: optional. A hint such as the allowed values, the accepted range, or the fields to remove.

The `details` array lists at most 100 problems. When a request has more, the last entry has the code `VALIDATION_ERROR` and reports how many problems it omitted.

The following table lists the detail codes:

| Detail code              | Meaning                                                      |
| ------------------------ | ------------------------------------------------------------ |
| `MISSING_REQUIRED_FIELD` | A required field is missing.                                 |
| `INVALID_TYPE`           | A field has the wrong type.                                  |
| `INVALID_ENUM`           | A field has a value outside its allowed set.                 |
| `OUT_OF_RANGE`           | A number, string, or array is too large or too small.        |
| `INVALID_FORMAT`         | A string doesn't match its format, such as an email or URL.  |
| `UNRECOGNIZED_KEYS`      | The object contains fields that the endpoint doesn't accept. |
| `INVALID_UNION`          | The value matches none of the accepted shapes.               |
| `CUSTOM_VALIDATION`      | The value fails an endpoint-specific rule.                   |
| `VALIDATION_ERROR`       | Any other validation problem.                                |

## Status codes

The following table lists the status codes that the API returns for errors and the codes that each one can carry:

| Status | Meaning                                                                                        | Codes                                                                                                      |
| ------ | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `400`  | The request is malformed or fails validation.                                                  | Validation detail codes in `details`, or an endpoint-specific `code`                                       |
| `401`  | The credential is missing, invalid, expired, or revoked.                                       | None                                                                                                       |
| `402`  | A spending control blocked the request.                                                        | `SPEND_LIMIT_EXCEEDED`, `PLATFORM_KEY_SPEND_EXCEEDED`, `DAILY_EVAL_LIMIT`                                  |
| `403`  | The credential lacks a permission or can't do the operation.                                   | `TEST_KEY_PERMISSION_DENIED`, or none with an `error` that names the missing permission                    |
| `404`  | The path or resource doesn't exist.                                                            | None                                                                                                       |
| `429`  | The request exceeded a rate or Test key limit.                                                 | `RATE_LIMIT_EXCEEDED`, `RATE_LIMITED`, `TEST_KEY_DAILY_LIMIT_EXCEEDED`, `TEST_KEY_LIFETIME_LIMIT_EXCEEDED` |
| `500`  | An unexpected server error occurred.                                                           | None. The body is `{"error": "Internal Server Error", "message": "Something went wrong"}`.                 |
| `503`  | A limit blocked an end-user request, or Runtype couldn't verify a credential for a short time. | `SERVICE_UNAVAILABLE`, or none for credential verification                                                 |

A `429` from a rate limit and a `503` from credential verification include a `Retry-After` header with the number of seconds to wait.

## Limit error codes

The following table lists the codes that the API returns when a limit refuses a request:

| Code                               | Status | `limitType` | Cause                                                                                          |
| ---------------------------------- | ------ | ----------- | ---------------------------------------------------------------------------------------------- |
| `RATE_LIMIT_EXCEEDED`              | `429`  | `rate`      | You started more executions in a 10-second window than your plan's burst rate allows.          |
| `SPEND_LIMIT_EXCEEDED`             | `402`  | `spend`     | Your month-to-date spend reached your monthly spend cap.                                       |
| `TEST_KEY_DAILY_LIMIT_EXCEEDED`    | `429`  | `daily`     | A Test API key or a test surface key reached its daily execution limit.                        |
| `TEST_KEY_LIFETIME_LIMIT_EXCEEDED` | `429`  | `lifetime`  | A Test API key reached its lifetime execution limit. This limit doesn't reset.                 |
| `RATE_LIMITED`                     | `429`  | None        | A surface key exceeded its per-minute or per-day request limit.                                |
| `PLATFORM_KEY_SPEND_EXCEEDED`      | `402`  | None        | Platform-key credit is unavailable, so model calls and tools that use platform keys stop.      |
| `DAILY_EVAL_LIMIT`                 | `402`  | None        | You reached your plan's daily limit on eval submissions. The count resets at midnight UTC.     |
| `SERVICE_UNAVAILABLE`              | `503`  | None        | An end user of your chat widget, client token, or surface reached one of the preceding limits. |

Runtype doesn't cap the number of executions that you run. The API doesn't return `DAILY_EXECUTION_LIMIT_EXCEEDED` or `MONTHLY_EXECUTION_LIMIT_EXCEEDED`.

### Limit response fields

A `RATE_LIMIT_EXCEEDED` or `SPEND_LIMIT_EXCEEDED` response has this shape:

**`402 response (abridged)`**

```json title="402 response (abridged)"
{
  "error": "Limit Exceeded",
  "message": "You've reached your monthly spend cap. Raise or clear it in billing settings to continue, or wait for the cap to reset at the start of next month.",
  "code": "SPEND_LIMIT_EXCEEDED",
  "limitType": "spend",
  "upgradeUrl": "/settings/billing",
  "resetsAt": "2026-10-01T00:00:00.000Z",
  "stats": {
    "tier": "startup",
    "periodType": "monthly",
    "spendLimitEnabled": true,
    "spendLimitCents": 5000,
    "atSpendLimit": true
  }
}
```

The value of `resetsAt` depends on the code:

* For `SPEND_LIMIT_EXCEEDED`, `resetsAt` is the start of the next month (UTC), when the spend cap resets.
* For `RATE_LIMIT_EXCEEDED`, `resetsAt` is the next midnight UTC. It isn't the time to retry. Wait for the number of seconds in the `Retry-After` header instead.

The Test key codes use a different body. It has `limitType` set to `daily` or `lifetime`, a `resetTime` for the daily limit, an `upgradeMessage`, and `stats` with the `remaining` and `limits` counts.

A `PLATFORM_KEY_SPEND_EXCEEDED` response includes a `blockReason` field with one of these values:

* `credit_exhausted`: your credit ran out and no automatic top-up replenished it.
* `trial_expired`: your free trial ended with no payment method on file.
* `auto_topup_failed`: an automatic top-up payment failed.

A `RATE_LIMITED` response includes a `retryAfter` field and a `Retry-After` header.

## Errors in streaming responses

When you request a stream, some errors arrive as events instead of an HTTP error status.

When a rate or spend limit refuses a streaming request before the run starts, the response has status `200`. The stream contains one `execution_error` event:

**`Refused streaming request (abridged)`**

```text title="Refused streaming request (abridged)"
event: execution_error
data: {"type":"execution_error","kind":"flow","error":{"code":"SPEND_LIMIT_EXCEEDED","message":"You've reached your monthly spend cap. Raise or clear it in billing settings to continue, or wait for the cap to reset at the start of next month."},"code":"SPEND_LIMIT_EXCEEDED","upgradeUrl":"/settings/billing"}
```

The `execution_error` event has these fields:

* `kind`: `flow` or `agent`.
* `error`: an object with `code` and `message`, or a string.
* `code`: the error code, when the error has one.
* `upgradeUrl`: the dashboard path for billing errors.
* `blockReason`: present for `PLATFORM_KEY_SPEND_EXCEEDED`.

A Test key limit returns a JSON `429` response, not an event, even when you request a stream.

After a run starts, errors arrive in these events:

* When a step fails, a `step_complete` event has `success` set to `false` and the message in `error`.
* When the run stops because of an error, the stream ends with an `execution_error` event. If platform-key credit runs out during the run, the event has the code `PLATFORM_KEY_SPEND_EXCEEDED`.
* When an Agent error is recoverable, the stream sends an `error` event with `recoverable` set to `true`, and the run continues.

For a non-streaming request, a failed run returns `success` set to `false`, with `error` and `code` fields that describe the failure. For all event types and fields, see the [API reference](/api-reference/overview).

## Errors for end users

Requests from a chat widget, a client token, a surface key, or a public surface don't show billing details. When one of these requests reaches a rate limit, spend cap, or platform-key credit limit, the API returns `503` with this body:

**`503 response for end users`**

```json title="503 response for end users"
{
  "error": "Service Unavailable",
  "message": "This assistant is temporarily unavailable. Please try again later.",
  "code": "SERVICE_UNAVAILABLE"
}
```

A streaming request from an end user gets an `execution_error` event with the same `code` and `message`.

## Next steps

* [Rate limits and usage](/user-guide/troubleshooting-faq/rate-limits-and-usage): fix `429` and `402` responses and retry after a burst-rate limit.
* [Common errors and solutions](/user-guide/troubleshooting-faq/common-errors-and-solutions): fix authentication, Flow, and Surface errors.
* [Authentication](/developer-guides/getting-started/authentication): send API keys and read the rate-limit headers.
* [Managing API keys](/user-guide/settings/managing-api-keys): create a Production key when a Test key reaches its limit.
* [Billing and plans](/user-guide/settings/billing-and-plans): change your spend cap and payment method.