> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reygrid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> HTTP status codes and error payloads returned by the ReyGrid API.

## Error shapes

The specification defines two error payloads.

<Tabs>
  <Tab title="401 — AuthErrorResponse">
    ```json theme={"system"}
    {
      "error": "Unauthorized",
      "code": "AUTH_REQUIRED"
    }
    ```

    | Field | Type | Description |
    | - | - | - |
    | `error` | string | Short error name |
    | `code` | string | Machine-readable code, e.g. `AUTH_REQUIRED` |
  </Tab>

  <Tab title="Other errors — ErrorResponse">
    ```json theme={"system"}
    {
      "success": false,
      "error": {
        "code": "INVALID_BODY",
        "message": "…",
        "list": [{}]
      }
    }
    ```

    | Field | Type | Description |
    | - | - | - |
    | `success` | boolean | `false` |
    | `error.code` | string | Machine-readable code |
    | `error.message` | string | Human-readable message |
    | `error.list` | array | Validation details. Present when `error.code` is `INVALID_BODY` |
    | `output`, `usage` | object | Optional |
  </Tab>
</Tabs>

## Status codes

| Status | Meaning | Returned by |
| - | - | - |
| `200` | Success | all endpoints |
| `400` | Invalid request body or query | chat, sources, search, feedback, `PATCH /agents/{agentId}`, `GET /usage` |
| `401` | API key missing or invalid | all authenticated endpoints |
| `402` | Not enough credits | `POST /agents/{AgentId}/chat`, `POST /agents/{AgentId}/search` |
| `403` | Not allowed: plan limit, model not on your plan, or a restricted API key | sources, `PATCH /agents/{agentId}`, any endpoint for restricted keys |
| `404` | Agent, source, conversation, message, or tool call not found | most agent endpoints |
| `409` | Tool call state conflict (already canceled or finished, or results still pending) | cancel tool call, `POST /agents/{AgentId}/chat` with tool results |
| `413` | File larger than the agent's remaining storage | `POST /agents/{agentId}/sources/files` |
| `429` | Too many requests, or the key's quota is used up | all endpoints |
| `500` | Internal server error | `POST /agents/{AgentId}/chat`, file uploads |
| `503` | The chat message couldn't be checked for harmful content | `POST /agents/{AgentId}/chat` |

## Error codes

| Code | Status | Meaning |
| - | - | - |
| `INVALID_BODY` | 400 | The body or query is invalid. `error.list` has the details per field |
| `CONTENT_BLOCKED` | 400 | The chat message was refused as harmful content (hate, harassment, sexual content, self-harm, violence or serious crime). Nothing is charged |
| `AGENT_NOT_FOUND` | 404 | The agent doesn't exist |
| `CONVERSATION_NOT_FOUND` | 404 | The conversation doesn't exist |
| `MESSAGE_NOT_FOUND` | 404 | The message doesn't exist (for feedback: no assistant message with this ID) |
| `SOURCE_NOT_FOUND` | 404 | The knowledge source doesn't exist |
| `TOOL_CALL_NOT_FOUND` | 404 | The tool call doesn't exist |
| `TOOL_CALL_ALREADY_CANCELED` | 409 | The tool call was already canceled |
| `TOOL_CALL_NOT_PENDING` | 409 | The tool call already finished, so it can't be canceled |
| `TOOL_CALL_ALREADY_EXECUTED` | 409 | Results were sent for tool calls that already have results |
| `PENDING_TOOL_CALLS` | 409 | The conversation has tool calls waiting for results. `error.ids` lists them |
| `PLAN_LIMIT_REACHED` | 403 | Your plan's storage or crawled-page limit is reached |
| `MODEL_NOT_AVAILABLE` | 403 | The model isn't available on your plan |
| `FILE_REQUIRED` | 400 | No file in the multipart request (field `file`) |
| `FILE_TYPE_NOT_ALLOWED` | 400 | Only PDF, DOC, DOCX and TXT files are accepted |
| `INVALID_FILE` | 400 | The file's type or content doesn't match its extension |
| `FILE_TOO_LARGE` | 413 | The file is larger than the storage the agent has left |
| `AGENT_NOT_ALLOWED` | 403 | This API key is restricted to other agents |
| `IP_NOT_ALLOWED` | 403 | This API key can't be used from your IP address |
| `KEY_EXPIRED` | 401 | This API key has expired |
| `INSUFFICIENT_CREDITS` | 402 | Not enough credits for the chat or search request |
| `QUOTA_EXCEEDED` | 429 | The key's credit quota is used up |
| `RATE_LIMITED` | 429 | Too many requests, slow down. See [Rate limits](#rate-limits) |
| `UNKNOWN_ERROR` | 500 | Something went wrong on our side. Credits charged for the request are refunded |
| `MODERATION_UNAVAILABLE` | 503 | The chat message couldn't be checked, so it wasn't sent to the model. Nothing is charged; try again |

## Rate limits

Requests are limited per account, across all of its API keys, by the plan of the key's owner:

| Plan | Requests per minute |
| - | - |
| Free | 10 |
| Starter | 60 |
| Pro | 300 |
| Business | 1,000 |

Over the limit, the API answers `429` with the code `RATE_LIMITED`. The `RateLimit-Remaining` and `RateLimit-Reset` response headers tell you how many requests are left in the current window and when it resets.

## Handling errors

```javascript theme={"system"}
const res = await fetch(url, { headers, method: "POST", body });

if (!res.ok) {
  const body = await res.json();
  if (res.status === 401) {
    // { error, code }
    throw new Error(`Auth failed: ${body.code}`);
  }
  // { success: false, error: { code, message, list? } }
  throw new Error(`${body.error.code}: ${body.error.message}`);
}
```

<Tip>
  Using an SDK? Errors are mapped to typed exceptions: [Python](/integrations/python/error-handling) · [TypeScript](/integrations/typescript/error-handling).
</Tip>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.