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

# Errors and close codes

> Every error a web session can return, what causes it, and how to fix it.

A web session can fail in three places:

| Where | What you get | Example |
| - | - | - |
| [Creating the session](#creating-a-session) | An HTTP error from `POST /api/v1/realtime/sessions` | `403 webcam_disabled` |
| [Connecting](#close-codes) | The WebSocket closes with a code | `4001` |
| [During the session](#error-messages) | A `{"type": "error"}` message. The session stays open. | `no_audio_received` |

<Tip>
  Many problems show no error at all. The session connects and the agent never speaks. See [Troubleshooting](/realtime/troubleshooting).
</Tip>

## Creating a session

`POST /api/v1/realtime/sessions` runs these checks. If one fails, no session is created.

| Status | Code | Cause | Fix |
| - | - | - | - |
| `401` | `unauthorized` | Missing or invalid API key | Check the `Authorization` header. |
| `402` | | Billing problem on the workspace | Fix billing in the dashboard. |
| `403` | `webcam_disabled` | `source: "camera"`, but the agent has the camera off | Turn on `enable_webcam`. |
| `403` | `screen_share_disabled` | `source: "screen"`, but the agent has screen share off | Turn on `enable_screen_share`. |
| `403` / `404` | | The agent does not exist, or belongs to another workspace | Check the `agent_id`. |
| `422` | | The request body is invalid. Unknown fields are rejected, so a typo like `"mode"` for `"source"` fails here. | Fix the body. |
| `429` | | More than 60 sessions in an hour, or 500 in a day | Wait for the time in the `Retry-After` header. |

The rate limit check runs last. So `402`, `403`, `404` and `422` do not use up a session.

## Close codes

When the server refuses a connection, it accepts the WebSocket and then closes it right away with a code. No message is sent first. So `onopen` fires even when the connection is refused. Read `event.code` and `event.reason` in `onclose`.

| Code | Reason | Cause | Fix |
| - | - | - | - |
| `4001` | Invalid authentication token | The token is missing, wrong, expired or already used. Or the agent moved to another workspace. | Create a new session for every connection. [More](#4001-invalid-token) |
| `4029` | Too many concurrent sessions for your plan | Your plan's limit on sessions running at the same time | Close sessions you no longer use. [More](#4029-too-many-connections) |
| `4029` | Too many connections | More than 20 connection attempts in 60 seconds from one IP address | Stop reconnecting in a loop. Wait a minute. |
| `4402` | Service unavailable | The workspace subscription is past due or unpaid | Fix billing in the dashboard. |
| `4028` | Plan limit, or Insufficient credits for a voice session | Usage limit reached, or not enough credit to start a voice session. The credit check does not apply to `text` sessions. | Top up or change plan. |
| `4003` | Screen sharing / Camera is not enabled for this agent | The setting was turned off after the session was created | Turn the setting back on, then create a new session. |
| `1011` | | The server could not start the agent session. If the voice service could not be reached, an [`upstream_unavailable`](#error-messages) error arrives just before the close. | Try again with a new session. |
| `1000` | | Normal close | Usually your own `ws.close()`. |

### 4001: invalid token

All token problems return `4001` with the same reason. Check these in order:

1. **The token was already used.** This is the most common cause during development. A token is used up by the first connection attempt, even if that attempt fails. Common causes:
   * React Strict Mode runs effects twice in development.
   * Hot reload runs the connect code again with the old token.
   * Your retry code reconnects with the same `ws_url`.
2. **The token expired.** It lasts 60 seconds. Creating the session on page load and connecting later on a click can take longer.
3. **The URL was changed.** Open `ws_url` exactly as returned.
4. **The agent was deleted or moved** between creating the session and connecting.

### 4029: too many connections

Read the `reason` to tell the two limits apart.

* **Per-IP limit** (20 attempts per 60 seconds). This check runs before the socket is accepted. So a browser usually reports code `1006` with an empty reason, not `4029`. If your reconnect loop gets `1006`, this is likely the cause.
* **Plan limit.** A session holds a slot until it disconnects. Close sessions with `ws.close(1000)` and stop all media tracks, including on `beforeunload`. A tab closed without cleanup can hold its slot for up to 2 hours.

### A 1000 close you did not expect

When the agent ends the conversation, the server sends `session_ended`. On voice, camera and screen sessions it does **not** close the socket. Call `ws.close()` yourself when you get `session_ended`.

A `1000` close that you did not start, with no `session_ended` before it, gives you nothing to go on. Log the last `error` message and the last turn you received.

## Error messages

During a session, the server sends an `error` message when it cannot use something you sent:

```json theme={"system"}
{ "type": "error", "code": "invalid_base64", "error": "..." }
```

**The session stays open.** The server drops that one message and carries on. Do not end the session on an error. Log `code` and show it while you develop. Match on `code`. The `error` text can change.

| Code | Cause | Fix |
| - | - | - |
| `invalid_json` | The message is not valid JSON. | Send `JSON.stringify({ mime_type, data })`. |
| `invalid_message` | The JSON is not an object. | Send an object with `mime_type` and `data`. |
| `missing_mime_type` | There is no `mime_type` field. A typo like `mimeType` also causes this. | Add `mime_type`. |
| `invalid_mime_type` | `mime_type` is not a string. | Send a string. |
| `unsupported_mime_type` | The type is not supported. `audio/webm`, `audio/wav`, `image/png` and `video/*` all fail. | Use `audio/pcm`, `image/jpeg` or `text/plain`. |
| `missing_data` | There is no `data` field. | Add `data`. |
| `invalid_data` | `data` is not a string. Often a `Uint8Array` that was passed to `JSON.stringify`. | Base64-encode the bytes first. |
| `invalid_base64` | `data` is not valid base64. Often a data URL cut off before its comma. A normal `data:image/jpeg;base64,` prefix is fine. | Send only the part after the comma. |
| `empty_payload` | `data` decodes to zero bytes. | Check the video has loaded and the audio graph is connected. |
| `binary_frame_unsupported` | You sent a binary WebSocket frame. | Send JSON text frames only. |
| `no_audio_received` | Images have arrived for about 8 seconds with no audio. Sent once. | Send microphone audio, or send a `text/plain` message. [More](/realtime/troubleshooting) |
| `forward_failed` | The message was valid, but the server could not pass it to the agent. | Safe to retry. If it keeps happening, contact support. |
| `upstream_unavailable` | Voice, camera and screen sessions only. The server could not reach the voice service, even after retrying. **This one ends the session:** the socket closes with `1011` right after it. | Show the `error` text, then start a new session. |

<Note>
  `no_audio_received` is checked when an image arrives, not on a timer. It fires on the first image that arrives at least 8 seconds after the first one. If you send two images and stop, you never get it.
</Note>

### Text sessions

A `text` session only sends two of these codes: `binary_frame_unsupported` and `missing_data`. It ignores audio and images without any error. If you send invalid JSON, the agent replies with a normal-looking apology message instead of an error. Check your own JSON on text sessions.

## Client library errors

`session.start()` rejects with an `EclatiraError`. Its `code` tells you what happened:

| `code` | Meaning |
| - | - |
| `mint_failed` | Your token endpoint failed or did not return `ws_url`. |
| `invalid_token` | Close code `4001` |
| `rate_limited` | Close code `4029` |
| `limit_reached` | Close code `4028` |
| `billing_blocked` | Close code `4402` |
| `source_not_enabled` | Close code `4003` |
| `server_error` | Close code `1011` |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.