<!-- https://leantools.ai/doc/errors · HTML twin of this page; the whole documentation: https://leantools.ai/llms-full.txt -->
# Errors

REST API

Every refusal carries a stable, machine-readable code. Branch on the code, show the message to a human, and never parse the message.

## Envelopes

### LeanConnect (web search, email, connectors), LeanData, LeanMachine, LeanVision, LeanMemory, model tiers and the tools API

```
{ "isSuccess": false, "errorMessage": "The account has no credits left. Top up or renew the subscription to continue.", "errorCode": "insufficient_credits" }
```

A data query answered as a JSON page may add `usage` when rows were fetched before the failure; a NDJSON stream that fails after its header ends with an `{"error":{code,message,status},"usage":{…}}` line. A held connector write adds `details { approvalId, expiresUtc, pollUrl }`.

### OpenAI-compatible endpoints

```
{ "error": { "message": "…", "type": "insufficient_quota", "code": "insufficient_credits" } }
```

### LeanBrowser

```
{ "error": "Description of the error.", "statusCode": 400 }
```

### MCP

Protocol failures are JSON-RPC errors (`{ jsonrpc, id, error: { code, message, data } }`); tool failures are results with `isError: true` whose text is `{"error":{"code","message","status"}}`.

## Admission codes (every service)

| Status | Code | Meaning | What to do |
| --- | --- | --- | --- |
| 401 | `authentication_error` | Missing, unknown or revoked API key | Send `Authorization: Bearer lt-…`; create a key in the console |
| 401 | `key_expired`, `key_revoked` | The key passed its expiry date, or was revoked (a held call approved after the fact fails with `key_revoked`) | Rotate or recreate the key in the console |
| 402 | `insufficient_credits` | The workspace has no credits left (or the in-flight reserve is exhausted) | Reload credits or turn on auto-reload |
| 402 | `key_cap_reached` | The key reached its monthly spend cap | Raise the cap or use another key |
| 402 | `tool_budget_reached` | The tool reached its monthly budget with pausing on | Raise the budget or turn pausing off |
| 403 | `service_not_allowed` | The key is not scoped to this service | Edit the key's access |
| 403 | `tool_disabled` | The tool is switched off for the workspace | Enable it under Tools & Connectors |
| 403 | `account_suspended`, `account_closed` | The workspace is not active | Contact support |
| 429 | `too_many_requests` | Rate limited at the edge | Honour `Retry-After` |

## Connector and approval codes

| Status | Code | Meaning |
| --- | --- | --- |
| 202 | `approval_pending` | The write is held for a human; poll `/api/v1/connectors/approvals/{id}` |
| 400 | `invalid_request`, `invalid_input`, `unknown_field`, `credential_required`, `invalid_credential`, `approval_requires_stored_credential`, `oauth_not_supported`, `expressions_not_supported` | Body shape, input validation, credential problems; a held write needs a stored credential, not an inline one |
| 403 | `connector_disabled`, `connector_paused`, `action_disabled`, `key_not_allowed`, `transport_not_allowed` | Host catalogue switch, workspace pause, workspace guardrails |
| 404 | `connector_not_found`, `action_not_found`, `credential_not_found`, `credential_type_not_found`, `approval_not_found` |  |
| 413 | `payload_too_large` |  |
| 422 | `connector_error` | The upstream rejected the request |
| 429 | `rate_limited`, `daily_cap_reached` | Per-connector limits set in the console |
| 502 / 504 | `connector_upstream_error`, `connector_timeout` |  |

## LeanData codes

See the [LeanData status codes](https://leantools.ai/doc/data#status-codes): `invalid_filter`, `subscription_required`, `dataset_not_found`, `response_too_large`, `provider_error` and the others.

## LeanModel (OpenAI envelope)

| Code | Meaning |
| --- | --- |
| `authentication_error` | Invalid, missing or revoked API key |
| `invalid_request_error` | Malformed request |
| `model_not_found` | The named tier does not exist (404), or the catalogue has no usable tier (400); use `GET /api/v1/models/tiers` |
| `model_not_configured` | The tier exists but the operator has not bound a model to it yet (400), for example a standard tier (`leanmodel-flash`, `leanmodel-default`) on a new host |
| `capability_not_supported` | The tier's model cannot take this request (400): image or audio parts on a tier without vision or hearing, an edit on a tier without image input, transcription on a tier that does not offer it |
| `unsupported_parameter` | A field LeanModel does not pass on (400), such as `mask` on image edits |
| `invalid_input` | Malformed media (400): bad base64, an audio format other than wav or mp3, a clip or upload over the size limit |
| `tier_not_in_package` | The package does not price the tier (403) |
| `insufficient_credits` | No credits left (402, type `insufficient_quota`). On a realtime audio socket the relay sends it as an `error` event (`error.code` is `insufficient_credits`) and closes with code 1008 |
| `too_many_streams`, `too_many_sockets` | The workspace's cap on open avatar streams or realtime sockets is reached (429) |
| `stream_not_found` | No avatar stream with that id belongs to the workspace (404) |
| `stream_closed` | The avatar stream has already been closed (409); create a new one |
| `stream_not_ready` | The avatar stream is still being created (409); retry in a moment |
| `upstream_error` | The avatar provider refused or failed the call (502); a stream that could not be created is not charged |
| `model_unavailable`, `billing_unavailable` | The avatar's model is no longer set up, or billing could not be opened and the new stream was closed again (503); retry |
| `upstream_unavailable` | The realtime model could not be reached (502, answered before the WebSocket upgrade); nothing is charged |
| `websocket_required` | The realtime endpoint was called without a WebSocket upgrade (400) |
| `server_error` | The AI provider failed |

Embeddings (`POST /api/v1/embeddings`) answer in the same envelope with their own codes: `invalid_input` (400), `payload_too_large` (413), `not_configured` (503, no embedding model set up on the host) and `upstream_error` (502, the model failed; nothing is charged), besides the admission codes above.

## LeanBrowser statuses

| Status | Meaning |
| --- | --- |
| 400 | Bad request (invalid JSON, missing fields) |
| 401 / 402 / 403 | Credential, credits, scope or workspace status |
| 404 | Route not matched, or a session that is not yours |
| 408 | Request timeout |
| 413 | Payload too large |
| 429 | `too_many_sessions`: concurrent WebSocket limit (default 4 per workspace) |
| 503 | System overloaded |

## LeanMachine, LeanVision and LeanMemory

Those services have their own vocabularies (`duplicate_key`, `no_capacity`, `too_many_streams`, `policy_refused`, `storage_cap_exceeded`, `quota_exceeded`, `upstream_error`, `upstream_timeout`, …), listed with each service in the [reference](https://leantools.ai/doc/api).
