# Errors and limits

> How errors arrive on MCP and REST, every error code with the fix, and the rate limits.

Source: https://rivomi.com/docs/reference/errors



Every error is a sentence the caller can act on, plus a stable code. Read the sentence: it usually
names the tool to call or the setting to change.

* **MCP:** a tool result with `isError: true`, not a JSON-RPC protocol error, so the model reads it
  and can correct its next call. The code follows the message as `(code: …)`.
* **REST:** `{ "error": "…", "code": "…" }` with the HTTP status below.

A wrong id is always an error that names the tool listing the right ids. It is never an empty
result.

## Codes [#codes]

| Code                 | Status | Meaning                                                                       | Fix                                                                                |
| -------------------- | ------ | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `unauthorized`       | 401    | No credential, or an expired or revoked one                                   | Reconnect, or use a valid key                                                      |
| `grant_revoked`      | 401    | The OAuth grant was disconnected in Settings › API                            | Reconnect and sign in                                                              |
| `insufficient_scope` | 403    | The credential lacks `write` or `send`                                        | A key or grant with that scope ([scopes](/connect/authentication#scopes))          |
| `not_found`          | 404    | No such id in this workspace                                                  | Take the id from the list tool the message names                                   |
| `not_configured`     | 409    | The workspace has no company profile yet                                      | The user fills in Settings › Workspace                                             |
| `no_source`          | 409    | Launching an agent with nothing to watch                                      | Add a source                                                                       |
| `conflict`           | 409    | The action does not apply in the current state (for example, pausing a draft) | Read the state first                                                               |
| `consent_required`   | 412    | Sending terms not accepted                                                    | A human accepts them under Settings › Senders ([guardrails](/concepts/guardrails)) |
| `no_seat`            | 409    | No connected LinkedIn sender to send from                                     | The user connects one under Settings › Senders                                     |
| (plan limit)         | 402    | A plan limit or the credit balance is exhausted; the message names which      | Wait for the reset or change plan. Nothing was half-done.                          |
| `rate_limited`       | 429    | Over the request budget                                                       | Wait `Retry-After` seconds                                                         |
| `org_deleted`        | 403    | The workspace no longer exists                                                | Nothing to retry                                                                   |

A `400` without a code is a bad argument. The message says which argument and why.

## Rate limits [#rate-limits]

600 requests a minute per workspace, plus a per-key limit. Over either, `429` with a
`Retry-After` header. Poll runs every minute or two, not in a tight loop.
