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

# Error handling

> Understanding API errors, HTTP status codes, error response formats, retry logic, and troubleshooting strategies for all cloro monitoring endpoints.

The cloro API uses standard [HTTP status codes](#http-status-codes) and consistent [error response formats](#error-response-formats) across all endpoints.

## HTTP status codes

| Status Code | Meaning               | Description                                                  |
| ----------- | --------------------- | ------------------------------------------------------------ |
| `200`       | Success               | Request completed successfully                               |
| `400`       | Bad Request           | Request validation failed                                    |
| `401`       | Unauthorized          | Authentication error (missing/invalid API key)               |
| `403`       | Forbidden             | Insufficient permissions or credits                          |
| `404`       | Not Found             | Endpoint/route not found                                     |
| `409`       | Conflict              | Resource conflict                                            |
| `429`       | Too Many Requests     | Concurrent or rate limit exceeded (depends on endpoint type) |
| `499`       | Client Closed Request | Request was canceled by client                               |
| `500`       | Internal Server Error | Server-side error                                            |
| `502`       | Bad Gateway           | External service error                                       |

## Error response formats

### Standard error response

Most errors follow this structure:

```json theme={null}
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": {
      // Additional context-specific information
    },
    "timestamp": "2025-01-15T12:00:00.000Z"
  }
}
```

### Validation error (400)

```json theme={null}
{
  "success": false,
  "error": "Request validation failed",
  "details": [
    {
      "field": "prompt",
      "message": "Prompt cannot be empty"
    }
  ]
}
```

### Canceled request (499)

```json theme={null}
{
  "success": false,
  "error": {
    "code": "REQUEST_CANCELED",
    "message": "Request was canceled by client",
    "timestamp": "2025-01-15T12:00:00.000Z"
  }
}
```

<Warning>
  **You will be charged for canceled requests**: If you receive a 499 status code,
  your account is still charged for the processing that occurred before cancellation.
  We charge for resources consumed, not just completed results.
</Warning>

### Internal error (500)

May return either format:

```json theme={null}
{
  "success": false,
  "error": "Maximum retries exceeded"
}
```

or

```json theme={null}
{
  "error": {
    "code": "INTERNAL_SERVER_ERROR",
    "message": "Internal server error",
    "timestamp": "2025-01-15T12:00:00.000Z"
  }
}
```

## Common error types

### Authentication errors (401)

| Error Code                   | Message                    | Cause                             |
| ---------------------------- | -------------------------- | --------------------------------- |
| `MISSING_API_KEY`            | Missing or invalid API key | No API key provided in request    |
| `INVALID_API_KEY_FORMAT`     | Invalid API key format     | API key format is incorrect       |
| `INVALID_OR_EXPIRED_API_KEY` | Invalid or expired API key | API key is invalid or has expired |

### Permission errors (403)

| Error Code                 | Message                  | Cause                            |
| -------------------------- | ------------------------ | -------------------------------- |
| `INSUFFICIENT_PERMISSIONS` | Insufficient permissions | API key lacks required scopes    |
| `INSUFFICIENT_CREDITS`     | Insufficient credits     | Account has insufficient credits |

### Rate Limiting (429)

**Concurrency limit exceeded** (monitor endpoints `/v1/monitor/*`):

```json theme={null}
{
  "error": {
    "code": "CONCURRENT_LIMIT_EXCEEDED",
    "message": "Concurrent limit exceeded",
    "details": {
      "limit": 10
    },
    "timestamp": "2025-01-15T12:00:00.000Z"
  }
}
```

**Rate limit exceeded** (all endpoints `/v1/*`):

```json theme={null}
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded",
    "details": {
      "limit": 1000,
      "window": "1s"
    },
    "timestamp": "2025-01-15T12:00:00.000Z"
  }
}
```

<Info>
  **Batch endpoint errors**

  The [batch task creation endpoint](/api-reference/endpoint/create-batch-tasks) uses a partial success model. Individual tasks can fail with per-task error codes (`VALIDATION_ERROR`, `RESOURCE_ALREADY_EXISTS`, `INSUFFICIENT_CREDITS`) inside a `200` response. See the [batch endpoint documentation](/api-reference/endpoint/create-batch-tasks#per-task-error-codes) for details.
</Info>

### External service errors (502)

```json theme={null}
{
  "error": {
    "code": "EXTERNAL_SERVICE_ERROR",
    "message": "External service error: OpenAI",
    "details": {
      "service": "OpenAI"
    },
    "timestamp": "2025-01-15T12:00:00.000Z"
  }
}
```

## Retry and cancellation

Our system automatically retries failed requests to ensure reliable task completion.

### Server-side retry behavior

* **Maximum retry attempts**: 10 attempts
* **Retry condition**: Automatic retry on transient failures

The retry process stops when either condition is met:

* 10 retry attempts have been exhausted
* The request completes successfully

### Client cancellation policy

<Warning>
  **Requests canceled by clients will be charged**: If you cancel a request
  after it has been submitted, you will still be charged for the processing that
  occurred before cancellation. We charge for the resources consumed, not just
  the final result.
</Warning>

### Client-side timeout guidance

<Info>
  **No client-side timeout needed**: Our retry mechanism handles transient
  failures automatically. You don't need to implement your own timeout logic.
</Info>

### Client-side retry for server errors

<Info>
  **Retry on 500/502 errors**: If you receive server errors (500) or bad gateway
  errors (502), implement retry logic with exponential backoff. These errors can
  occur because of transient issues like temporary network problems or external
  service timeouts. Our system retries automatically, and client-side retries add
  another layer of resilience.
</Info>

## Validation rules

### Prompt validation

| Rule                        | Error Message                                    |
| --------------------------- | ------------------------------------------------ |
| Must be 1-10,000 characters | "Prompt cannot be empty" or "Prompt is too long" |

### Country code validation

| Rule                                                                                                             | Error Message          |
| ---------------------------------------------------------------------------------------------------------------- | ---------------------- |
| Must be a valid **uppercase** ISO 3166-1 alpha-2 code (e.g., `"US"`, `"GB"`) — lowercase values are not accepted | "Invalid country code" |

### Include parameter validation

| Parameter                         | Valid Values      | Error Message      |
| --------------------------------- | ----------------- | ------------------ |
| `include.markdown`                | `true` or `false` | "Expected boolean" |
| `include.rawResponse` (ChatGPT)   | `true` or `false` | "Expected boolean" |
| `include.searchQueries` (ChatGPT) | `true` or `false` | "Expected boolean" |

## Troubleshooting

### Common issues and solutions

**401 Unauthorized**

* Check that your API key is included in the Authorization header
* Verify the API key format is correct
* Ensure the API key hasn't expired

**403 Insufficient Credits**

* Check your credit balance via response headers
* Top up your account credits

**429 Too Many Requests**

For all endpoints:

* Monitor rate limit headers (`X-RateLimit-Remaining`) to avoid hitting the 1,000/sec per-endpoint limit
* Implement request throttling to stay within the rate limit
* The counter resets every second, so brief delays can help avoid rate limit errors

For monitor endpoints (additional limits):

* Monitor concurrency headers to stay within your plan's concurrent request limit
* Implement proper retry logic with exponential backoff
* Consider queuing requests if you hit concurrency limits

**400 Validation Errors**

* Ensure prompt text is between 1-10,000 characters
* Use valid ISO 3166-1 alpha-2 country codes
* Check that include parameters are boolean values

**500/502 Server Errors**

* Implement retry logic for transient failures
* Monitor status pages for service availability
* Contact support if errors persist

## Common questions

### Why are some of my requests failing with 500 errors?

500 errors indicate server-side issues. Here's what they typically mean and how to handle them:

* Provider issues: the upstream AI provider is experiencing problems.
* Invalid request format: your request doesn't match the API specification.
* Temporary infrastructure issues: brief service disruptions or maintenance.

Best practice for production: Always implement retry logic with exponential backoff. Our system retries failed requests automatically (up to 10 attempts), and client-side retries add another layer of resilience for 5xx errors.

### Where do I see logs for successful requests?

Every monitor request — sync and async — is logged to the [dashboard](https://dashboard.cloro.dev) with the request id, provider, prompt, country, status code, credits charged, and latency. Successful (`2xx`) requests show up alongside failures so you can audit usage end-to-end. Entries typically appear within a minute; if a request seems missing, refresh — heavy load occasionally delays ingestion but does not drop entries.

### Is there a bulk export of request logs?

No. The dashboard shows logs in a paginated view only — there is no CSV export or bulk download. For log analysis at scale, log the `X-Request-ID` response header on every API call alongside your own metadata at the point of call. This gives you a permanent audit trail keyed to cloro's internal request IDs for support lookups.

### An async task returned `200 OK` but the result looks wrong. What does that mean?

`200 OK` from `GET /v1/async/task/{taskId}` only confirms the task record exists. The task's outcome lives inside `task.status` — see [task states](/guides/making-requests/async#step-1-make-an-api-request) for the full lifecycle and [the `COMPLETED` vs. upstream-error FAQ](/guides/making-requests/async#a-task-came-back-completed-but-the-result-looks-like-an-upstream-error-what-happened) for how to detect degraded provider responses.

### What's the expected success rate for API requests?

Our average success rate is >99% across all providers. However, several factors can affect success rates:

1. Provider stability: Upstream AI provider reliability varies by provider
2. Geographic region: Some regions may have different success rates depending on infrastructure
3. Time of day: Peak usage times may affect performance

Best practice for production: Always implement retry logic with exponential backoff. Our system retries failed requests automatically (up to 10 attempts), and client-side retries add another layer of resilience for 5xx errors.
