Skip to main content

Error Handling

The SDK exposes error-related behavior through three main channels: Use 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: Do not treat every warning as a failed call. Media/signaling recovery warnings are intentionally emitted before the SDK attempts recovery, so your application can show a short degraded/reconnecting state while the SDK handles the recovery path.
Version note: The structured error and warning system (TELNYX_ERROR_CODES, telnyx.warning, TelnyxError) was introduced after v2.25.25. Exponential-backoff reconnection and browser online/offline hints (see Reconnection Behavior) ship in the next release. If you are on v2.25.25, see Error handling in v2.25.25 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

Error event payload structure

Every telnyx.error event is one of two shapes. Always check isMediaRecoveryErrorEvent(event) first, because the media-recovery variant carries callable recovery helpers. Standard error event (the common case):
Media-permission recovery event (only when mediaPermissionsRecovery.enabled is set and getUserMedia() fails while answering):
The structured error object (TelnyxError / ITelnyxError) exposes:
fatal vs recoverable — two distinct fields, two distinct purposes:
  • event.error.fatal (always present on every error): tells your app whether the SDK has a recovery path. true = the SDK will not recover — take action now. false = the SDK is handling it — wait or continue.
  • event.recoverable (only on media-permission recovery events): signals the app can recover via the resume()/reject() helpers. Only event.recoverable === true is meaningful; recoverable is absent on standard errors — do not branch on event.recoverable === false.
Recommended listener order: (1) check isMediaRecoveryErrorEvent(event) first, (2) then check event.error.fatal to decide whether to take action or wait, (3) then branch on event.error.code for tailored UX.

Getting and filtering errors by code

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:

Fatal errors are situations the SDK will not recover from. When a fatal error fires, the affected call or session is dead — the SDK will not retry, reconnect, or reattach on its own. Your application must take the action described below. Every error event includes event.error.fatal — a boolean that tells your app whether the SDK has a recovery path. true means the situation is terminal and you must act; false means the SDK is handling it (wait or continue). The Fatal? column below mirrors this field.
Uncommon errors — when to investigate. SDP_CREATE_OFFER_FAILED (40001), SDP_CREATE_ANSWER_FAILED (40002), SDP_SET_LOCAL_DESCRIPTION_FAILED (40003), SDP_SET_REMOTE_DESCRIPTION_FAILED (40004), PEER_CLOSED_DURING_INIT (44005), and WEBSOCKET_CONNECTION_FAILED (45001) are not expected during normal operation. If any of these recurs a few times or more, share the call with Telnyx support for investigation — their occurrence is most likely not caused by user actions and may indicate a browser, network, or server-side issue.
Errors that are not fatal by default (the SDK handles or continues): HOLD_FAILED (44001), BYE_SEND_FAILED (44003), SUBSCRIBE_FAILED (44004), WEBSOCKET_ERROR (45002), GATEWAY_FAILED (45004), ICE_RESTART_FAILED (47001), NETWORK_OFFLINE (48001). Two exceptions to know:
  • AUTHENTICATION_REQUIRED (46003) is non-fatal by default but becomes fatal when autoReconnect: false. Re-authenticate using client.login().
  • The three media errors (4200142003) become recoverable (non-fatal) when mediaPermissionsRecovery.enabled is set.
Re-authenticate without recreating the instance. For LOGIN_FAILED (46001), INVALID_CREDENTIALS (46002), and AUTHENTICATION_REQUIRED (46003), use client.login() on the existing connection:

Errors and warnings you should handle explicitly

These are the high-impact errors and warnings we recommend handling explicitly in every production integration. They are also marked ⚠️ in the reference tables below. Important errors (handle on telnyx.error): Important warnings (handle on telnyx.warning):

Error code reference

Each error below is classified as fatal or non-fatal and includes what the SDK does automatically versus what you should do.

SDP errors

Media errors

Call-control errors

ICE restart errors

WebSocket and transport errors

autoReconnect is enabled by default. Unless you explicitly set autoReconnect: false, the SDK handles reconnection automatically for WEBSOCKET_ERROR, GATEWAY_FAILED, and signaling-health recovery. You only need to call client.connect() manually if you disabled autoReconnect or after RECONNECTION_EXHAUSTED.

Authentication and session errors

Re-authenticate without recreating the instance. For LOGIN_FAILED (46001), INVALID_CREDENTIALS (46002), and AUTHENTICATION_REQUIRED (46003), use client.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.

Imports

Warning event payload structure

Every warning event includes a structured warning object and the SDK sessionId. When a warning is associated with a specific call, callId is included. Recovery-related warnings add reason (and source for signaling recovery) for diagnostics:
The structured warning object (ITelnyxWarning) exposes: Use warning.code for application logic. Use warning.message, warning.causes, and warning.solutions for support tooling or user-facing troubleshooting copy.

Getting and filtering warnings by code

Warning code reference

Network quality warnings

Data-flow warnings

Call connection warnings

Authentication and session warnings

Signaling health and recovery warnings

Signaling health warnings are emitted when the SDK detects a half-dead WebSocket during an active call — the browser still reports the socket as 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 (SIGNALING_RECOVERY_REQUIRED).
  • If signaling is healthy but media is unhealthy, it attempts ICE restart (MEDIA_RECOVERY_REQUIRED).
  • It does not run both recovery paths at the same time.
Recovery is driven by SDK-owned health signals (liveness probe timeout, critical request timeout, peer failure, no-RTP). Browser online/offline events are treated as low-confidence hints and may accelerate a signaling health probe, but they do not directly trigger recovery. Your application should keep the current call visible, show a reconnecting/degraded state, and wait for the next callUpdate, telnyx.ready, warning, or final hangup before cleaning up the UI.

Call Termination Data

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

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:

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: Example:

Reconnection Behavior

On telnyx.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(). Automatic reconnect stops after maxReconnectAttempts attempts (default: 10), or runs indefinitely when maxReconnectAttempts: 0.

Reconnect backoff

Reconnect attempts use exponential backoff with jitter (not a fixed/random delay):
  • Base delay starts at ~1s and doubles per attempt (~1s → ~2s → ~4s → ~8s → ~16s), capped at 30s.
  • ±25% jitter is applied to avoid thundering-herd reconnects.
  • The backoff counter resets only on a confirmed healthy registration (REGED), not merely on socket open.

Browser online/offline handling

Browser online/offline events are treated as low-confidence hints, not direct recovery triggers:
  • offline emits the NETWORK_OFFLINE (48001) error for backward compatibility/telemetry and may accelerate a signaling health probe. It does not force a reconnect.
  • online clears the browser-reported offline state for diagnostics but does not trigger recovery.
  • Recovery starts only from SDK-owned health evidence: liveness probe timeout, critical request timeout, peer failure, or no-RTP.

Socket close/error dedupe

When a socket fails, browsers commonly emit both SocketError and SocketClose for the same disconnect. The SDK dedupes these by socket generation so a duplicate event cannot clear an already-scheduled reconnect timer or schedule a redundant reconnect. Stale events from an older, already-replaced socket are ignored.

Gateway retry behavior

  • UNREGED / NOREG: Up to 5 registration retries with exponential backoff. After that, LOGIN_FAILED (46001).
  • FAILED / FAIL_WAIT / TIMEOUT: GATEWAY_FAILED (45004) emitted on first detection. The SDK retries with exponential backoff until 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.

Clearing reconnect stickiness

By default, the SDK reconnects to the same b2bua-rtc instance. To break this stickiness and route to a different instance:
Note: clearReconnectToken() and skipLastVoiceSdkId are 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

Error events in v2.25.25

In v2.25.25, errors are emitted through telnyx.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:
Error-related notification types:

Authentication errors in v2.25.25

Login errors are emitted on telnyx.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 differs from the current version:
  • autoReconnect is enabled by default; the SDK automatically reconnects unless you set autoReconnect: false
  • Reconnect uses a fixed/random 2-6 second delay (current SDK uses exponential backoff with jitter, capped at 30s)
  • Browser online/offline events directly drive reconnect (current SDK treats them as low-confidence hints)
  • No maxReconnectAttempts option (current SDK defaults to 10 attempts and supports maxReconnectAttempts: 0 for unlimited attempts)
  • No clearReconnectToken() method
  • No skipLastVoiceSdkId option
  • keepConnectionAliveOnSocketClose is available

Migrating from v2.25.25 to the latest

If you are upgrading from v2.25.25 to the latest version:
  1. Replace telnyx.notification error handling — use telnyx.error for fatal errors and telnyx.warning for non-fatal conditions. Keep telnyx.notification for call lifecycle only.
  2. Replace notification.type === 'userMediaError' handling with telnyx.error listener switching on event.error.code (42001, 42002, 42003).
  3. Replace notification.type === 'peerConnectionFailureError' handling with telnyx.warning listener for PEER_CONNECTION_FAILED (33004).
  4. Replace notification.type === 'signalingStateClosed' handling with telnyx.warning listener for the appropriate warning code.
  5. Replace ERROR_TYPE.invalidCredentialsOptions checks with event.error.code === TELNYX_ERROR_CODES.INVALID_CREDENTIALS (46002). Use client.login() to re-authenticate without recreating the TelnyxRTC instance.
  6. Import new symbols: TelnyxError, TELNYX_ERROR_CODES, TELNYX_WARNING_CODES, isMediaRecoveryErrorEvent.
  7. Note SESSION_NOT_REATTACHED is an error, not a warning: in v2.26.0+ it is TELNYX_ERROR_CODES.SESSION_NOT_REATTACHED (48501) on telnyx.error (fatal), not a warning. UNKNOWN_REATTACHED_SESSION (35002) is the separate warning.