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

# Errors

> Cuadra AI API errors follow RFC 7807 Problem Details format. Includes HTTP status codes, common errors, and retry logic examples.

## Error Format

```json theme={null}
{
  "type": "about:blank",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Invalid or expired token."
}
```

| Field    | Description                |
| -------- | -------------------------- |
| `type`   | Error type URI             |
| `title`  | Short error name           |
| `status` | HTTP status code           |
| `detail` | Human-readable explanation |

***

## HTTP Status Codes

| Code | Title                 | Retryable | Description                           |
| ---- | --------------------- | --------- | ------------------------------------- |
| 400  | Bad Request           | No        | Invalid request format                |
| 401  | Unauthorized          | No        | Invalid or missing token              |
| 402  | Payment Required      | No        | Insufficient credits                  |
| 403  | Forbidden             | No        | Valid token, insufficient permissions |
| 404  | Not Found             | No        | Resource doesn't exist                |
| 409  | Conflict              | No        | Resource already exists               |
| 422  | Unprocessable Entity  | No        | Validation failed                     |
| 429  | Too Many Requests     | **Yes**   | Rate limit exceeded                   |
| 500  | Internal Server Error | **Yes**   | Server error                          |

***

## Common Errors

### 401 - Invalid Token

```json theme={null}
{
  "title": "Unauthorized",
  "status": 401,
  "detail": "Invalid or expired token."
}
```

**Fix:** Refresh your M2M token or verify the JWT session is valid.

### 403 - Missing Scope

```json theme={null}
{
  "title": "Forbidden",
  "status": 403,
  "detail": "Missing required scope: chat:invoke"
}
```

**Fix:** Request credentials with the required scope.

### 429 - Rate Limited

```json theme={null}
{
  "title": "Too Many Requests",
  "status": 429,
  "detail": "Rate limit exceeded. Retry after 60 seconds."
}
```

**Headers:**

```
Retry-After: 60
X-RateLimit-Remaining: 0
```

**Fix:** Wait for `Retry-After` seconds.

### 402 - Insufficient Credits

```json theme={null}
{
  "title": "Insufficient Credits",
  "status": 402,
  "detail": "Insufficient credits. Required: 75 credits. Available: 50 credits."
}
```

**Fix:** Purchase credits at [dashboard.cuadra.ai](https://dashboard.cuadra.ai) or wait for monthly reset.

***

## Rate Limits

| Scope            | Limit               |
| ---------------- | ------------------- |
| Per organization | 300 requests/minute |
| Per user         | 60 requests/minute  |

***

## Retry Logic

Implement exponential backoff for 429 and 5xx errors:

<CodeGroup>
  ```python Python theme={null}
  import httpx
  import time
  import random

  def request_with_retry(url, headers, data, max_retries=3):
      for attempt in range(max_retries):
          response = httpx.post(url, headers=headers, json=data)
          
          if response.status_code == 429:
              retry_after = int(response.headers.get('Retry-After', 60))
              time.sleep(retry_after + random.uniform(0, 1))
              continue
          
          if response.status_code >= 500:
              time.sleep((2 ** attempt) + random.uniform(0, 1))
              continue
          
          return response
      
      raise Exception("Max retries exceeded")
  ```

  ```typescript Node.js theme={null}
  async function requestWithRetry(url, options, maxRetries = 3) {
    for (let attempt = 0; attempt < maxRetries; attempt++) {
      const response = await fetch(url, options);
      
      if (response.status === 429) {
        const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
        await new Promise(r => setTimeout(r, (retryAfter + Math.random()) * 1000));
        continue;
      }
      
      if (response.status >= 500) {
        await new Promise(r => setTimeout(r, (2 ** attempt + Math.random()) * 1000));
        continue;
      }
      
      return response;
    }
    throw new Error('Max retries exceeded');
  }
  ```
</CodeGroup>

***

## Best Practices

1. **Check status before parsing** — Don't assume success
2. **Implement retries** — For 429 and 5xx errors
3. **Log error details** — Include `detail` message for debugging
4. **Show user-friendly messages** — Don't expose raw errors to users
5. **Monitor error rates** — Alert on spikes

***

## FAQ

### What format do Cuadra AI errors use?

All errors follow RFC 7807 Problem Details format with `type`, `title`, `status`, and `detail` fields.

### How should I handle rate limits (429)?

Implement exponential backoff. Wait the time specified in `Retry-After` header, then retry. See retry logic examples above.

### What does "insufficient\_credits" mean?

Your organization has run out of credits. Purchase more at [dashboard.cuadra.ai](https://dashboard.cuadra.ai) or upgrade your plan.

***

## Related

<CardGroup cols="2">
  <Card title="Authentication" icon="lock" href="/api-reference/authentication">
    Fix auth errors
  </Card>

  <Card title="Credits" icon="coins" href="/billing/credits">
    Handle credit errors
  </Card>
</CardGroup>
