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

# Error Handling

> How to handle errors, warnings, and connection failures with the Telnyx WebRTC JS SDK.

# Error Handling

The SDK exposes error-related behavior through three main channels:

| Event                 | Purpose                                                | Recommended use                                |
| --------------------- | ------------------------------------------------------ | ---------------------------------------------- |
| `telnyx.error`        | Fatal or blocking SDK errors                           | Show actionable errors, retry, re-authenticate |
| `telnyx.warning`      | Non-fatal quality, connectivity, and token warnings    | Show degraded-state UI, collect telemetry      |
| `telnyx.notification` | Call lifecycle updates and compatibility notifications | Drive call UI and hangup handling              |

Use `telnyx.ready` to know when the client is authenticated and the gateway is ready. Do not treat readiness as a notification case.

***

## Structured Errors (`telnyx.error`)

`telnyx.error` is the primary error surface. Listen for it to handle authentication failures, media errors, and connection issues.

### Imports

```javascript theme={null}
import {
  SwEvent,
  TelnyxError,
  TELNYX_ERROR_CODES,
  isMediaRecoveryErrorEvent,
} from '@telnyx/webrtc';
```

### Basic example

```javascript theme={null}
client.on(SwEvent.Error, (event) => {
  if (isMediaRecoveryErrorEvent(event)) {
    openPermissionsDialog({
      deadline: event.retryDeadline,
      onRetry: () => event.resume(),
      onCancel: () => event.reject(),
    });
    return;
  }

  if (!(event.error instanceof TelnyxError)) {
    showErrorMessage('An unknown SDK error occurred.');
    return;
  }

  switch (event.error.code) {
    case TELNYX_ERROR_CODES.NETWORK_OFFLINE:
      showErrorMessage('You appear to be offline.');
      break;
    case TELNYX_ERROR_CODES.AUTHENTICATION_REQUIRED:
      showErrorMessage('Session expired. Please authenticate again.');
      break;
    default:
      showErrorMessage(event.error.message);
  }
});
```

### Media permission recovery

When `mediaPermissionsRecovery.enabled` is configured and `getUserMedia()` fails while answering a call, the error event includes `recoverable: true` with `resume()` and `reject()` callbacks:

```javascript theme={null}
const client = new TelnyxRTC({
  login_token: jwt,
  mediaPermissionsRecovery: {
    enabled: true,
    timeout: 10000,
  },
});

client.on(SwEvent.Error, (event) => {
  if (isMediaRecoveryErrorEvent(event)) {
    // Show a dialog asking the user to grant microphone permission
    // event.retryDeadline is the timestamp by which they must act
    showPermissionDialog({
      onGrant: () => event.resume(),
      onDismiss: () => event.reject(),
    });
  }
});
```

***

## Error Code Reference

### SDP errors

| Code    | Name                                | Typical trigger                           |
| ------- | ----------------------------------- | ----------------------------------------- |
| `40001` | `SDP_CREATE_OFFER_FAILED`           | `createOffer()` failed                    |
| `40002` | `SDP_CREATE_ANSWER_FAILED`          | `createAnswer()` failed                   |
| `40003` | `SDP_SET_LOCAL_DESCRIPTION_FAILED`  | `setLocalDescription()` failed            |
| `40004` | `SDP_SET_REMOTE_DESCRIPTION_FAILED` | `setRemoteDescription()` failed           |
| `40005` | `SDP_SEND_FAILED`                   | Invite/answer signaling could not be sent |

### Media errors

| Code    | Name                                 | Typical trigger                                   |
| ------- | ------------------------------------ | ------------------------------------------------- |
| `42001` | `MEDIA_MICROPHONE_PERMISSION_DENIED` | Browser or OS denied microphone permission        |
| `42002` | `MEDIA_DEVICE_NOT_FOUND`             | Missing/disconnected device or invalid `deviceId` |
| `42003` | `MEDIA_GET_USER_MEDIA_FAILED`        | `getUserMedia()` failed for another reason        |

### Call-control errors

| Code    | Name                      | Typical trigger                              |
| ------- | ------------------------- | -------------------------------------------- |
| `44001` | `HOLD_FAILED`             | Hold request failed                          |
| `44002` | `INVALID_CALL_PARAMETERS` | Required call params were missing or invalid |
| `44003` | `BYE_SEND_FAILED`         | BYE could not be sent                        |
| `44004` | `SUBSCRIBE_FAILED`        | Verto subscribe failed                       |

### WebSocket and transport errors

| Code    | Name                          | Typical trigger                          |
| ------- | ----------------------------- | ---------------------------------------- |
| `45001` | `WEBSOCKET_CONNECTION_FAILED` | WebSocket connection failed              |
| `45002` | `WEBSOCKET_ERROR`             | Browser `ws.onerror` fired               |
| `45003` | `RECONNECTION_EXHAUSTED`      | Reconnect attempts exhausted             |
| `45004` | `GATEWAY_FAILED`              | Gateway reported `FAILED` or `FAIL_WAIT` |

### Authentication and session errors

| Code    | Name                      | Typical trigger                                 |
| ------- | ------------------------- | ----------------------------------------------- |
| `46001` | `LOGIN_FAILED`            | Login rejected or never reached ready state     |
| `46002` | `INVALID_CREDENTIALS`     | Client-side login validation failed             |
| `46003` | `AUTHENTICATION_REQUIRED` | Request sent before auth or after auth was lost |
| `48001` | `NETWORK_OFFLINE`         | Browser `offline` event fired                   |
| `49001` | `UNEXPECTED_ERROR`        | Unclassified failure during peer/call setup     |

***

## Structured Warnings (`telnyx.warning`)

Warnings are not fatal. They describe degraded behavior, quality issues, or situations that may need user action before the session breaks.

### Basic example

```javascript theme={null}
import { SwEvent, TELNYX_WARNING_CODES } from '@telnyx/webrtc';

client.on(SwEvent.Warning, ({ warning, callId }) => {
  if (warning.code === TELNYX_WARNING_CODES.TOKEN_EXPIRING_SOON) {
    refreshToken();
    return;
  }

  if (warning.code === TELNYX_WARNING_CODES.PEER_CONNECTION_FAILED) {
    showWarningBanner('Call is reconnecting');
    return;
  }

  console.warn(`[${warning.code}] ${warning.name}: ${warning.message}`);
});
```

### Warning code reference

#### Network quality warnings

| Code    | Name               | Typical trigger                    |
| ------- | ------------------ | ---------------------------------- |
| `31001` | `HIGH_RTT`         | RTT stayed above threshold         |
| `31002` | `HIGH_JITTER`      | Jitter stayed above threshold      |
| `31003` | `HIGH_PACKET_LOSS` | Packet loss stayed above threshold |
| `31004` | `LOW_MOS`          | MOS stayed below threshold         |

#### Data-flow warnings

| Code    | Name                 | Typical trigger                       |
| ------- | -------------------- | ------------------------------------- |
| `32001` | `LOW_BYTES_RECEIVED` | Remote audio bytes stopped increasing |
| `32002` | `LOW_BYTES_SENT`     | Local audio bytes stopped increasing  |

#### Connectivity warnings

| Code    | Name                       | Typical trigger                            |
| ------- | -------------------------- | ------------------------------------------ |
| `33001` | `ICE_CONNECTIVITY_LOST`    | ICE connection state became `disconnected` |
| `33002` | `ICE_GATHERING_TIMEOUT`    | ICE gathering safety timeout fired         |
| `33003` | `ICE_GATHERING_EMPTY`      | No candidates were collected               |
| `33004` | `PEER_CONNECTION_FAILED`   | Peer connection state became `failed`      |
| `33005` | `ONLY_HOST_ICE_CANDIDATES` | SDP contained only host ICE candidates     |

#### Authentication and session warnings

| Code    | Name                     | Typical trigger                  |
| ------- | ------------------------ | -------------------------------- |
| `34001` | `TOKEN_EXPIRING_SOON`    | JWT expires within 120 seconds   |
| `35001` | `SESSION_NOT_REATTACHED` | Active call lost after reconnect |

***

## Call Termination Data

When a call reaches `hangup`, inspect these fields on the `Call` object:

| Field       | Type     | Meaning                                               |
| ----------- | -------- | ----------------------------------------------------- |
| `cause`     | `string` | High-level cause (`USER_BUSY`, `CALL_REJECTED`, etc.) |
| `causeCode` | `number` | Numeric cause code                                    |
| `sipCode`   | `number` | SIP response code when available                      |
| `sipReason` | `string` | SIP reason phrase when available                      |

Common causes:

| Cause                | Meaning                                    |
| -------------------- | ------------------------------------------ |
| `NORMAL_CLEARING`    | Expected call completion                   |
| `USER_BUSY`          | Remote party was busy                      |
| `CALL_REJECTED`      | Remote party rejected the call             |
| `NO_ANSWER`          | Call timed out unanswered                  |
| `UNALLOCATED_NUMBER` | Dialed number is invalid or does not exist |

***

## Socket Events

### `telnyx.socket.close`

Delivers the browser `CloseEvent`. During a forced safety cleanup, the SDK emits a synthetic abnormal close with `code: 1006` and `wasClean: false`.

Useful close codes:

| Code   | Meaning          |
| ------ | ---------------- |
| `1000` | Normal closure   |
| `1001` | Going away       |
| `1006` | Abnormal closure |
| `1011` | Internal error   |

### `telnyx.socket.error`

Delivers `{ error: ErrorEvent, sessionId: string }`. Browsers expose very little information for WebSocket errors. The SDK also emits `telnyx.error` with code `45002` (`WEBSOCKET_ERROR`) when `ws.onerror` fires.

***

## Connection State Helpers

The browser session exposes WebSocket state helpers on `client.connection`:

| Getter                        | Meaning                |
| ----------------------------- | ---------------------- |
| `client.connection.connected` | WebSocket is in `OPEN` |
| `client.connection.isAlive`   | `CONNECTING` or `OPEN` |
| `client.connection.isDead`    | `CLOSING` or `CLOSED`  |

Example:

```javascript theme={null}
const placeCall = (destinationNumber) => {
  if (!client.connection.connected) {
    showErrorMessage('Still connecting to Telnyx. Please try again shortly.');
    return;
  }

  client.newCall({ destinationNumber });
};
```

***

## Reconnection Behavior

On `telnyx.socket.close` or `telnyx.socket.error`, the SDK clears subscriptions and resets gateway readiness state. If `autoReconnect` is enabled, the browser session schedules `connect()` after `reconnectDelay` (1000ms).

### Gateway retry behavior

* **UNREGED / NOREG:** Up to 5 registration retries, each delayed 2-6 seconds randomly. After that, `LOGIN_FAILED` (`46001`).
* **FAILED / FAIL\_WAIT:** `GATEWAY_FAILED` (`45004`) emitted on first detection. Up to 5 retries with 2-6 second random delay before `RECONNECTION_EXHAUSTED` (`45003`).

### Keeping media alive

If `keepConnectionAliveOnSocketClose` is `true`, the SDK preserves active peer connections while signaling reconnects. Recovery can create a new `Call` object with `recoveredCallId`.

***

## See Also

* [Call Class](/development/webrtc/js-sdk/reference/call) — Call control methods
* [Handle Reconnection](/development/webrtc/js-sdk/how-to/handle-reconnection) — Reconnection guide
* [Monitor Call Quality](/development/webrtc/js-sdk/how-to/monitor-call-quality) — Quality monitoring
* [Server Events](/development/webrtc/js-sdk/reference/sw-events) — Low-level signaling events
