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 |
telnyx.ready to know when the client is authenticated and the gateway is ready. Do not treat readiness as a notification case.
What your application should react to
For production integrations, handle these events explicitly:| Event | React in UI? | Retry/recover yourself? | Notes |
|---|---|---|---|
telnyx.ready | Yes | No | Connection is authenticated and ready for calls. Hide reconnecting state here. |
telnyx.error | Yes | Sometimes | Fatal/blocking errors. Follow the error code guidance below. |
telnyx.warning | Yes for call-affecting warnings | Usually no | Degraded but non-fatal. The SDK continues running and often starts automatic recovery. |
telnyx.notification with type: 'callUpdate' | Yes | No | Source of truth for call states, hangups, SIP cause/causeCode, and recovered calls. |
telnyx.socket.close / telnyx.socket.error | Optional | No unless autoReconnect: false | Useful for telemetry and reconnecting UI; wait for telnyx.ready or RECONNECTION_EXHAUSTED. |
Version note: The structured error and warning system (TELNYX_ERROR_CODES,telnyx.warning,TelnyxError) was introduced after v2.25.25. If you are on v2.25.25, see the Error handling in v2.25.25 section below.
Structured Errors (telnyx.error)
telnyx.error is the primary error surface. Listen for it to handle authentication failures, media errors, and connection issues.
Imports
Basic example
Media permission recovery
WhenmediaPermissionsRecovery.enabled is configured and getUserMedia() fails while answering a call, the error event includes recoverable: true with resume() and reject() callbacks:
Error Code Reference
Each error below is classified as fatal or recoverable and includes guidance on what action you should take versus what the SDK handles automatically.SDP errors
| Code | Name | Fatal? | Customer action | SDK behavior |
|---|---|---|---|---|
40001 | SDP_CREATE_OFFER_FAILED | Fatal | Show error to user; retry with client.newCall() | Call is not established |
40002 | SDP_CREATE_ANSWER_FAILED | Fatal | Show error to user; the inbound call cannot be answered | Call is rejected |
40003 | SDP_SET_LOCAL_DESCRIPTION_FAILED | Fatal | Show error to user; retry the call | Call setup fails |
40004 | SDP_SET_REMOTE_DESCRIPTION_FAILED | Fatal | Show error to user; retry the call | Call setup fails |
40005 | SDP_SEND_FAILED | Fatal | Show error to user; retry the call | Signaling could not be sent |
Media errors
| Code | Name | Fatal? | Customer action | SDK behavior |
|---|---|---|---|---|
42001 | MEDIA_MICROPHONE_PERMISSION_DENIED | Fatal unless mediaPermissionsRecovery is enabled | Prompt user to grant microphone permission in browser/OS settings | Call fails; if mediaPermissionsRecovery.enabled, a recoverable error is emitted instead |
42002 | MEDIA_DEVICE_NOT_FOUND | Fatal | Check that a microphone is connected and the deviceId is valid | Call fails |
42003 | MEDIA_GET_USER_MEDIA_FAILED | Fatal unless mediaPermissionsRecovery is enabled | Check browser permissions and device availability; retry | Call fails; if mediaPermissionsRecovery.enabled, a recoverable error is emitted instead |
Call-control errors
| Code | Name | Fatal? | Customer action | SDK behavior |
|---|---|---|---|---|
44001 | HOLD_FAILED | Non-fatal per call | Retry hold operation | Hold is not applied |
44002 | INVALID_CALL_PARAMETERS | Fatal | Fix call parameters before retrying | Call is not established |
44003 | BYE_SEND_FAILED | Non-fatal | Call is still hung up locally; no action needed | Local hangup completes but BYE signal may not reach the server |
44004 | SUBSCRIBE_FAILED | Fatal | Check connection state; may need to reconnect | Cannot subscribe to call events |
44005 | PEER_CLOSED_DURING_INIT | Fatal | Retry the call | Peer connection closed before call setup completed |
ICE restart errors
| Code | Name | Fatal? | Customer action | SDK behavior |
|---|---|---|---|---|
47001 | ICE_RESTART_FAILED | Fatal for the call | Show call failed/disconnected state; ask the user to retry the call or change networks | Media recovery could not complete |
WebSocket and transport errors
| Code | Name | Fatal? | Customer action | SDK behavior |
|---|---|---|---|---|
45001 | WEBSOCKET_CONNECTION_FAILED | Fatal for session | Check network connectivity; call client.connect() to retry | Session is not established |
45002 | WEBSOCKET_ERROR | Fatal for session | Show reconnecting UI; SDK auto-reconnects by default (autoReconnect is enabled by default). If you disabled autoReconnect, call client.connect() manually. Wait for telnyx.ready to confirm recovery | WebSocket error occurred; SDK schedules connect() after a random 2-6 second delay when autoReconnect is not disabled |
45003 | RECONNECTION_EXHAUSTED | Fatal for session | All automatic reconnect attempts exhausted. Call client.disconnect() then client.connect() to start a fresh connection, or recreate the client instance | Automatic reconnect stopped after maxReconnectAttempts attempts; default is 10 attempts, set maxReconnectAttempts: 0 for unlimited attempts |
45004 | GATEWAY_FAILED | Fatal for session | Show reconnecting UI; SDK auto-reconnects by default (autoReconnect is enabled by default). If you disabled autoReconnect, call client.connect() manually. Wait for telnyx.ready to confirm recovery | Gateway reported FAILED or FAIL_WAIT; SDK continues retrying when autoReconnect is not disabled |
autoReconnectis enabled by default. Unless you explicitly setautoReconnect: false, the SDK handles reconnection automatically forWEBSOCKET_ERROR,GATEWAY_FAILED, and signaling-health recovery. You only need to callclient.connect()manually if you disabledautoReconnector afterRECONNECTION_EXHAUSTED.
Authentication and session errors
| Code | Name | Fatal? | Customer action | SDK behavior |
|---|---|---|---|---|
46001 | LOGIN_FAILED | Fatal for session | Re-authenticate using client.login() without recreating the instance | Registration never reached ready state |
46002 | INVALID_CREDENTIALS | Fatal for session | Fix credential parameters; re-authenticate using client.login() | Login was rejected before request was sent |
46003 | AUTHENTICATION_REQUIRED | Fatal for session | Re-authenticate using client.login({ creds: { login_token: newToken } }) without recreating the instance | Request was sent before auth completed or after auth was lost |
48001 | NETWORK_OFFLINE | Fatal for session | Restore network connectivity; SDK auto-reconnects when back online | Browser offline event fired |
49001 | UNEXPECTED_ERROR | Fatal | Check logs for details; retry the operation | Unclassified failure during peer/call setup |
Re-authenticate without recreating the instance. ForLOGIN_FAILED(46001),INVALID_CREDENTIALS(46002), andAUTHENTICATION_REQUIRED(46003), useclient.login()to re-authenticate on the existing connection:
Structured Warnings (telnyx.warning)
Warnings are never fatal. They describe degraded behavior, quality issues, or situations that may need user action before the session breaks. The SDK continues operating after emitting a warning.
Basic example
Warning event payload
Every warning event includes a structuredwarning object and the SDK sessionId. When a warning is associated with a specific call, callId is also included. Recovery-related warnings may include reason and source fields for diagnostics:
warning.code for application logic. Use warning.message, warning.causes, and warning.solutions for support tooling or user-facing troubleshooting copy.
Warning code reference
Network quality warnings
| Code | Name | Auto-recovered? | Customer action |
|---|---|---|---|
31001 | HIGH_RTT | May self-resolve | Show quality indicator; no immediate action needed |
31002 | HIGH_JITTER | May self-resolve | Show quality indicator; no immediate action needed |
31003 | HIGH_PACKET_LOSS | May self-resolve | Show quality indicator; no immediate action needed |
31004 | LOW_MOS | May self-resolve | Show quality indicator; consider advising user |
31005 | LOW_LOCAL_AUDIO | May self-resolve | Show microphone-level indicator; ask the user to check mute/input gain or selected microphone |
Data-flow warnings
| Code | Name | Auto-recovered? | Customer action |
|---|---|---|---|
32001 | LOW_BYTES_RECEIVED | May self-resolve on reconnect | Check remote party; show degraded audio indicator |
32002 | LOW_BYTES_SENT | May self-resolve on reconnect | Check local microphone; show degraded audio indicator |
Connectivity warnings
| Code | Name | Auto-recovered? | Customer action |
|---|---|---|---|
33001 | ICE_CONNECTIVITY_LOST | SDK attempts ICE reconnect | Show reconnecting indicator; wait for recovery or PEER_CONNECTION_FAILED |
33002 | ICE_GATHERING_TIMEOUT | May self-resolve | Check firewall/STUN/TURN config; show warning |
33003 | ICE_GATHERING_EMPTY | No | Check network/firewall settings; STUN/TURN may be blocked |
33004 | PEER_CONNECTION_FAILED | May recover — SDK may attempt ICE restart | Show reconnecting/degraded UI; wait for SDK recovery; only clean up after final hangup or call termination |
33005 | ONLY_HOST_ICE_CANDIDATES | No | Check STUN/TURN config; call may work on local network only |
33006 | ANSWER_WHILE_PEER_ACTIVE | No | Ensure answer() is called only once per call; disable the answer button after the first click; check that answer() is not invoked from multiple event handlers |
33007 | DUPLICATE_INBOUND_ANSWER | No | Keep a single active TelnyxRTC instance for inbound calls; disconnect old clients before replacing them; answer only one duplicate inbound notification |
33008 | ICE_CANDIDATE_PAIR_CHANGED | Usually yes | Log candidate path changes and monitor quality; frequent changes indicate unstable network, VPN, NAT rebinding, or relay fallback |
Authentication and session warnings
| Code | Name | Auto-recovered? | Customer action |
|---|---|---|---|
34001 | TOKEN_EXPIRING_SOON | No, but preventable | Refresh the token before it expires; you have ~120 seconds |
35001 | SESSION_NOT_REATTACHED | No | Active calls were lost after reconnect; clean up call UI |
Signaling health and recovery warnings
| Code | Name | Auto-recovered? | Customer action |
|---|---|---|---|
36001 | SIGNALING_HEALTH_PROBE_TIMEOUT | SDK force-closes the WebSocket and reconnects | Show reconnecting/degraded UI; do not place a second call; wait for telnyx.ready and callUpdate recovery |
36002 | SIGNALING_REQUEST_TIMEOUT | SDK force-closes the WebSocket and reconnects for critical call-control requests | Show reconnecting/degraded UI; collect reason/source for support |
36003 | SIGNALING_RECOVERY_REQUIRED | SDK reconnects signaling and reattaches active calls | Show short interruption state; wait for call reattach or final hangup |
36004 | MEDIA_RECOVERY_REQUIRED | SDK attempts ICE restart without reconnecting the socket | Show media reconnecting indicator; keep call UI active until recovery or final hangup |
OPEN, but no signaling bytes are flowing after a network interface change, VPN change, NAT timeout, or proxy/load-balancer drop. The SDK decides one recovery path:
- If signaling is unhealthy, it reconnects the WebSocket and reattaches active calls.
- If signaling is healthy but media is unhealthy, it attempts ICE restart.
- It does not run both recovery paths at the same time.
callUpdate, telnyx.ready, warning, or final hangup before cleaning up the UI.
Call Termination Data
When a call reacheshangup, inspect these fields on the Call object:
| Field | Type | Meaning |
|---|---|---|
cause | string | null | High-level cause (USER_BUSY, CALL_REJECTED, etc.) |
causeCode | number | null | Numeric cause code |
sipCode | number | null | SIP response code when available |
sipReason | string | null | SIP reason phrase when available |
| 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 onclient.connection:
| Getter | Meaning |
|---|---|
client.connection.connected | WebSocket is in OPEN |
client.connection.isAlive | CONNECTING or OPEN |
client.connection.isDead | CLOSING or CLOSED |
Reconnection Behavior
Ontelnyx.socket.close or telnyx.socket.error, the SDK clears subscriptions and resets gateway readiness state. autoReconnect is enabled by default; unless you set autoReconnect: false, the SDK automatically schedules connect() after a randomized 2-6 second delay. Automatic reconnect stops after maxReconnectAttempts attempts (default: 10), or runs indefinitely when maxReconnectAttempts: 0.
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 beforeRECONNECTION_EXHAUSTED(45003).
Keeping media alive
IfkeepConnectionAliveOnSocketClose is true, the SDK preserves active peer connections while signaling reconnects. Recovery can create a new Call object with recoveredCallId.
Clearing reconnect stickiness
By default, the SDK reconnects to the sameb2bua-rtc instance. To break this stickiness and route to a different instance:
Note:clearReconnectToken()andskipLastVoiceSdkIdare available in@telnyx/webrtc@2.26.4.
Error Handling in v2.25.25
Important: If you are using SDK version 2.25.25, the error handling architecture is fundamentally different from the current version. This section documents the v2.25.25 error surface.
What is different in v2.25.25
| Feature | v2.25.25 | v2.26.0+ |
|---|---|---|
| Structured error codes | Not available | TELNYX_ERROR_CODES with numeric codes |
telnyx.warning event | Not available | Available with TELNYX_WARNING_CODES |
TelnyxError class | Not available | Structured error class with .code, .name, .message |
isMediaRecoveryErrorEvent() | Not available | Available for media permission recovery |
SDK_ERRORS / SDK_WARNINGS | Not available | Available for error/warning metadata |
| Primary error surface | telnyx.error (raw Error) + telnyx.notification | telnyx.error (structured) + telnyx.warning |
Error events in v2.25.25
In v2.25.25, errors are emitted throughtelnyx.error and telnyx.notification:
telnyx.error — Session-level errors with raw Error objects (no .code property):
telnyx.notification — Carries both call lifecycle updates and error information. This is the only recommended way to handle media, peer connection, and signaling errors in v2.25.25. Do not listen for telnyx.rtc.mediaError, telnyx.rtc.peerConnectionFailureError, or telnyx.rtc.peerConnectionSignalingStateClosed directly — those are internal events. Use telnyx.notification instead:
notification.type | Meaning | Fatal? | Customer action |
|---|---|---|---|
userMediaError | Media device access failed | Yes (for the call) | Prompt user for microphone permission; the SDK hangs up the call automatically |
peerConnectionFailureError | Peer connection failed | Peer connection not recoverable, but call may be recovered | Show reconnecting/degraded UI; the call may be restored automatically by the server via attach with recovering state; only clean up after a final hangup/call update confirms loss |
signalingStateClosed | Peer signaling state closed | Peer connection not recoverable, but call may still be recovered by server | Show reconnecting/degraded UI; the call may recover through auto-created recovering call with the same call_id; only clean up after a final hangup/call update confirms loss |
Authentication errors in v2.25.25
Login errors are emitted ontelnyx.error with a type field for invalid credentials. You can re-authenticate using client.login() without recreating the TelnyxRTC instance:
Reconnection in v2.25.25
Reconnection behavior is the same as the current version with these differences:autoReconnectis enabled by default; the SDK automatically reconnects unless you setautoReconnect: false- No
maxReconnectAttemptsoption (current SDK defaults to 10 automatic reconnect attempts and supportsmaxReconnectAttempts: 0for unlimited attempts) - No
clearReconnectToken()method - No
skipLastVoiceSdkIdoption keepConnectionAliveOnSocketCloseis available
Migrating from v2.25.25 to the latest
If you are upgrading from v2.25.25 to the latest version:- Replace
telnyx.notificationerror handling — usetelnyx.errorfor fatal errors andtelnyx.warningfor non-fatal conditions. Keeptelnyx.notificationfor call lifecycle only. - Replace
notification.type === 'userMediaError'handling withtelnyx.errorlistener switching onevent.error.code(42001,42002,42003). - Replace
notification.type === 'peerConnectionFailureError'handling withtelnyx.warninglistener forPEER_CONNECTION_FAILED(33004). - Replace
notification.type === 'signalingStateClosed'handling withtelnyx.warninglistener for the appropriate warning code. - Replace
ERROR_TYPE.invalidCredentialsOptionschecks withevent.error.code === TELNYX_ERROR_CODES.INVALID_CREDENTIALS(46002). Useclient.login()to re-authenticate without recreating theTelnyxRTCinstance. - Import new symbols:
TelnyxError,TELNYX_ERROR_CODES,TELNYX_WARNING_CODES,isMediaRecoveryErrorEvent. - If you need media permission recovery for inbound calls, enable
mediaPermissionsRecoveryand handleisMediaRecoveryErrorEvent(event). - Treat
telnyx.readyas the only readiness signal. ThevertoClientReadynotification type is no longer emitted ontelnyx.notification.
telnyx.rtc.mediaError, telnyx.rtc.peerConnectionFailureError, telnyx.rtc.peerConnectionSignalingStateClosed) are still emitted for backward compatibility but should not be used for new integrations.
See Also
- Call Class — Call control methods
- Handle Reconnection — Reconnection guide
- Monitor Call Quality — Quality monitoring
- Server Events — Low-level signaling events