# Handle errors

## Error model[​](#error-model "Direct link to Error model")

Rejected promises and the `error` event carry a [`NablaConnectError`](/connect/sdk/reference/classes/NablaConnectError.md) with a stable `code` and an optional `reason`. Branch on `code`.

* `create` throws a `TypeError` when the iframe does not belong to a window. Nothing else throws.
* The `error` event is a [`NablaConnectErrorEvent`](/connect/sdk/reference/classes/NablaConnectErrorEvent.md), a `CustomEvent` with the error on `detail`. It fires for an error after `ready` that no command owns, like `CONTEXT_CHANGED`.
* Failures before `ready` reject `ready` only. A rejected `ready` ends the client: create another one to retry. `TIMEOUT` is the exception, see below.
* After `ready`, an unexpected failure inside the SDK is an `UNKNOWN` error event, and the client keeps running.

## Error codes[​](#error-codes "Direct link to Error codes")

### `COMMAND_REJECTED`[​](#command-rejected "Direct link to command-rejected")

The iframe refused or failed the command. `reason` is `NOT_ALLOWED`, `STALE_STATE`, `INVALID_SESSION`, `EXPORT_FAILED`, or `UNKNOWN` (an unexpected failure while running it). A refusal because the iframe is busy is reported as `BUSY`, and a command the iframe could not read as `INVALID_MESSAGE`. Re-read `getCurrentState()` and retry if the command is still allowed.

### `BUSY`[​](#busy "Direct link to busy")

Another command is running, the state is transitional, another encounter is recording, an audio backup is processing, or the provider is finishing the Nabla onboarding. Wait for the next `stateChanged`.

### `TIMEOUT`[​](#timeout "Direct link to timeout")

No answer in 30 seconds, for `ready` or for a command. A `ready` `TIMEOUT` does not end the client: when the iframe was only waiting on the provider, the first state still arrives on `stateChanged`, and commands called before it reject with `TIMEOUT`. If nothing comes, check `target_origin` and the allowlist, then create a new client. A command `TIMEOUT` has `reason` `NO_RESULT` and means the outcome is unknown, not that it failed. See [Troubleshooting](#troubleshooting).

### `CONTEXT_CHANGED`[​](#context-changed "Direct link to context-changed")

Another client was created on the same iframe, another document booted in it, or another origin loaded in it. Call `destroy()` and create a new client. A reload of the iframe does not cause it: the client reconnects.

### `UNSUPPORTED_VERSION`[​](#unsupported-version "Direct link to unsupported-version")

This SDK version cannot talk to the current iframe. Upgrade `@nabla/connect-sdk`.

### `INVALID_ORIGIN`[​](#invalid-origin "Direct link to invalid-origin")

The `url` you passed to `create` is not HTTPS (HTTP is allowed only on `localhost`, `127.0.0.1`, and `[::1]`) or has an opaque origin. Fix the URL.

### `INVALID_MESSAGE`[​](#invalid-message "Direct link to invalid-message")

The iframe could not read a command. A command rejected for this reason rejects its promise. When the iframe cannot tell which command it was, the error arrives on the `error` event only. The pending command is not failed by it: if its own result is lost, it rejects with `TIMEOUT`. Report it to <connect@nabla.com>.

### `DESTROYED`[​](#destroyed "Direct link to destroyed")

`destroy()` was called. Nothing to do.

### `UNKNOWN`[​](#unknown "Direct link to unknown")

The iframe sent something this SDK version does not know (upgrade `@nabla/connect-sdk`), the answer to a command could not be read (read the state before retrying), the browser refused to post, or an unexpected failure happened inside the SDK. After `ready`, the client keeps running.

## Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting")

### `ready` rejects with `TIMEOUT`[​](#ready-rejects-with-timeout "Direct link to ready-rejects-with-timeout")

The provider may just be slow: a first sign-in or the Nabla onboarding can take more than 30 seconds. The client keeps listening after this rejection, and the first state arrives on `stateChanged`. Keep the iframe visible. If no state ever comes, check, in this order:

1. Nabla enabled the SDK for your organization, and your origin shows in the allowlist of Nabla Connect Admin. Admin does not show the SDK setting yet: ask <connect@nabla.com> if unsure.
2. `POST /encounters` was called with `target_origin`, and it equals the origin of the page that embeds the iframe.
3. That origin is in the allowlist, with the same scheme, hostname, and port.
4. The `url` you passed to `create` is an encounter URL, not a settings URL. Check `iframe.src` and the network tab.
5. No intermediate frame sits between your page and the iframe.

### No action is available during the provider's first session[​](#no-action-is-available-during-the-providers-first-session "Direct link to No action is available during the provider's first session")

The Nabla onboarding covers the encounter. The state is the real one, usually `NOT_STARTED`, with an empty `availableActions`, and commands reject with [`BUSY`](#busy). Keep the iframe visible. The actions come back in a `stateChanged` once the onboarding is over.

### A command rejects with `TIMEOUT`[​](#a-command-rejects-with-timeout "Direct link to a-command-rejects-with-timeout")

The iframe did not answer within 30 seconds. This does not mean the command failed: see [Timeouts](/connect/sdk/guides/commands.md#timeouts).

* Read `stateChanged` or `getCurrentState()` to learn the outcome. The new state arrives when the command ends.
* A new command before then rejects with `BUSY`.
* The SDK has no liveness signal. Silence is normal. Do not take it, or a timeout, for a crash.
