# Errors and limits

When a tool call fails, Cademí MCP returns an error with a stable `code`, a message, and the API `request_id` when there is one. This page lists the codes, what to do for each, and the limits on response size, time, and load.

## Error format

A failed call is a tool result with `isError: true`. Its text starts with the code and the message, and `structuredContent` carries the error as an object:

```json
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Too many requests.",
    "retryable": true,
    "api_code": "rate_limit_exceeded",
    "request_id": "01J8Z3ZQ4H8K2M0T1S9P7YQF5C",
    "retry_after_seconds": 12,
    "details": { "blocked_by": ["key"] }
  }
}
```

| Field | Description |
|---|---|
| `code` | One of the codes below. |
| `message` | What happened, in English. |
| `retryable` | `true` when the same call may succeed later. |
| `api_code` | The code of the API error, when the API returned one. See [Errors](https://cademi.dev/api/errors.md#codes). |
| `request_id` | The identifier of the API call, when there is one. |
| `retry_after_seconds` | How long to wait before retrying, when known. |
| `details` | More information, depending on the error: the invalid fields (`fields`), the candidates of an ambiguous reference (`candidates`), the missing permissions (`missing_permissions`), or the API's `reason` and `blocked_by`. |

## Codes

| Code | Retryable | Meaning | What to do |
|---|---|---|---|
| `AUTHENTICATION_REQUIRED` | No | The authorization of the connection is missing, expired, or revoked, or the API rejected it. | Connect the client again and authorize it ([Connect a client](https://cademi.dev/mcp/connect.md#check-the-connection)). |
| `PERMISSION_DENIED` | No | The administrator does not have the permission, or the API refused the operation for this account, for example because the operation runs only in a sandbox account or the record is a read-only replica. `api_code` says which. | Use a connection authorized by an administrator with the permission, or grant it. See [Authorization and permissions](https://cademi.dev/mcp/authorization.md#permissions). |
| `INVALID_ARGUMENT` | No | The input was rejected. For validation errors, `details.fields` lists the invalid fields. | Correct the input. Retrying the same call fails again. |
| `RESOURCE_NOT_FOUND` | No | The resource does not exist or is not accessible. For a composite tool, no student or product matches the reference. | Check the ID or the name, or search with `users_list` or `products_list`. |
| `AMBIGUOUS_REFERENCE` | No | A composite tool found several students or products for the reference. `details.candidates` lists up to 10. | Choose a candidate and call the tool again with its ID ([How students and products are found](https://cademi.dev/mcp/tools.md#how-students-and-products-are-found)). |
| `CONFLICT` | No | The call conflicts with the current state: the resource changed since the `revision` you sent in `if_match`, the transition is not allowed, the resource already exists, or an idempotency key was reused with a different request. | Read the current state and decide again. |
| `RATE_LIMITED` | Yes | The account reached an API limit. | Wait `retry_after_seconds` when present, then retry. See [Limits, quotas, and retention](https://cademi.dev/api/limits.md). |
| `CLI_TIMEOUT` | Yes | An API call made by the tool did not finish within the time limit. | Retry. For a call that changes data, check first whether the change was applied, or retry with the same `idempotency_key`. |
| `CLI_FAILED` | No | The call could not be completed for a reason that no other code covers, or it was cancelled. | Retry once. If it fails again, report it with the `request_id`. |
| `CAPACITY_EXHAUSTED` | Yes | The server is at capacity. | Retry after `retry_after_seconds`. |
| `OUTPUT_TOO_LARGE` | No | The API result is too large to return. | Narrow the query with filters or a smaller `limit`, and page with `cursor`. |
| `API_UNAVAILABLE` | Yes | The API or the Cademí authorization server is temporarily unavailable, or the API failed with a server error. | Retry later. If `api_code` is `result_uncertain`, see [Uncertain results](https://cademi.dev/mcp/errors-and-limits.md#uncertain-results). |
| `INTERNAL_ERROR` | No | An unexpected error in the MCP server. | Try again later. If it persists, report it. |

The error codes of the API behind `api_code` are listed in [Errors](https://cademi.dev/api/errors.md#codes).

### Uncertain results

When a call that changes data fails with `api_code` set to `result_uncertain`, the change may have been applied. The error then has `retryable: false`. A retry is safe only with the same `idempotency_key` as the first call: if the first attempt was recorded, the API returns its result and applies nothing new. When you omit `idempotency_key`, a new key is generated for each call, so set it yourself on a call you may need to retry. Without the first key, check whether the change was applied before you call again. The same applies to a `CLI_TIMEOUT` on a call that changes data. How idempotency works in the API is described in [Errors](https://cademi.dev/api/errors.md#what-to-do-for-each-class).

## Request IDs

When an error comes from the API, it keeps the API's `request_id`. It is the same identifier as the `X-Request-Id` header and the audit entry of the call. Composite tools also include the `request_id` in each entry of `warnings` for a part that could not be read.

Include the `request_id` when you report a problem ([Report a problem](https://cademi.dev/mcp/overview.md#report-a-problem)).

## Response size

A tool result has a size limit. When a result goes over it:

1. Very long text values are shortened, and each one ends with a note that says how many characters were omitted.
2. If the result is still too large, items are removed from the end of its largest list until it fits.

A shortened result says so with `truncated: true` and a `truncation` object:

```json
{
  "truncated": true,
  "truncation": {
    "hint": "Some items were omitted to fit the response size limit. Call again with a smaller `limit` and follow `page.next_cursor` to see every item.",
    "arrays": [{ "path": "items", "returned": 38, "omitted": 12 }]
  }
}
```

| Field | Description |
|---|---|
| `hint` | How to get the rest. |
| `strings_clipped` | How many text values were shortened. |
| `arrays` | For each list that lost items, its path in the result, how many items were returned, and how many were omitted. |

When the API result is far above the limit, the tool returns `OUTPUT_TOO_LARGE` instead. In both cases, ask for less: a smaller `limit`, filters, or the next page.

Composite tools also read a bounded amount of data. A list they could not read in full has `complete: false`, and `product_structure` expands a bounded number of modules ([`product_structure`](https://cademi.dev/mcp/tools.md#product_structure)).

## Time and load

- **Time limit.** Each API call a tool makes has a time limit. A call that goes over it fails with `CLI_TIMEOUT`. Composite tools make several API calls, some of them in parallel.
- **Cancellation.** If your client cancels a tool call, the server stops it, with the code `CLI_FAILED`. A change that the call already sent to the API may still be applied.
- **Server capacity.** When the server is busy, a call waits briefly for a slot. If none frees up, it fails with `CAPACITY_EXHAUSTED` and `retry_after_seconds`.
- **API limits.** Tool calls count toward the API limits of your account, like calls from any other client. See [Limits, quotas, and retention](https://cademi.dev/api/limits.md).
