> For the complete documentation index, see [llms.txt](https://docs.digitalsamba.com/reference/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.digitalsamba.com/reference/sdk/events/apperror.md).

# appError

Emitted when something unexpected or not allowed happens in the room.

#### Here is a list of the possible error names:

* `permissions-rejected` -> emitted when user tries to screen share, but browser doesn't have enough permissions for it
* `not-allowed` -> emitted when a not allowed action was requested by the user. For example if a user tries to start a recording and recording is not supported in the room, you will receive a `not-allowed` type.
* `forbidden-action` -> emitted when a forbidden action was requested by the user. For example if a user tries to end a session and doesn't have a permission to do so, then the `forbidden-action` type.
* `authorization-failed` -> emitted when a user's authorization into the room is rejected — for example a display name that fails room validation.
* `command-failed` -> emitted when an SDK method call fails to be processed on the room side. The `data.command` field tells you which method failed. **If `data.command` is `"connect"`, treat this as fatal**: the room did not finish loading and will not recover on its own — reload the iframe or show your own error state rather than treating it as a single failed call.
* `virtual-bg` -> emitted for virtual background problems. Historically this covered invalid `configureVirtualBackground()` options only; it now also reports that a requested virtual background **was not applied**. See [Virtual background not applied](#virtual-background-not-applied) below.

#### Sample payload

```json
{
  "type": "appError",
  "data": {
      "name": "not-allowed",
      "message": "Recording disabled. You’ll need to edit this room’s properties to record sessions in this room",
      "data": {
         "type": "recording"
      }
  }
}
```

Starting from `v0.0.58` of `@digitalsamba/embedded-sdk`, `not-allowed` can also occur when you call a session-only command (recording, screenshare, whiteboard actions, remote-user actions, hand raise/lower, and similar) before you've joined the session, or after you've left or the session has ended. In that case `data.type` is `"not-joined"` and `data` also includes the command name:

```json
{
  "type": "appError",
  "data": {
    "name": "not-allowed",
    "message": "Command \"removeUser\" requires an active session",
    "data": {
      "type": "not-joined",
      "command": "removeUser"
    }
  }
}
```

If your integration inspects `data` on `not-allowed` errors, make sure it tolerates `data.type` values it doesn't recognize yet and the additional `data.command` field — don't assume `data` only ever has a `type` key.

```json
{
  "type": "appError",
  "data": {
      "name": "forbidden-action",
      "message": "Forbidden action. This participant is not allowed to end session",
      "data": {
         "type": "end-session"
      }
  }
}
```

```json
{
  "type": "appError",
  "data": {
    "name": "authorization-failed",
    "message": "User authorization failed",
    "data": {
      "message": "<underlying error message>"
    }
  }
}
```

```json
{
  "type": "appError",
  "data": {
    "name": "command-failed",
    "message": "Failed to process SDK command \"startRecording\"",
    "data": {
      "command": "startRecording"
    }
  }
}
```

`message` on `command-failed` always follows the template `Failed to process SDK command "<command>"`, where `<command>` is the exact method/command name you called.

## Virtual background not applied

A virtual background you requested can end up not being applied — either because the participant's device cannot run virtual backgrounds at all, or because applying it failed. Previously this was silent: the participant simply kept their raw camera and your application was never told. It is now reported as an `appError` with `name: "virtual-bg"` and a `data.reason` field.

This matters most when you pass `enforce: true` to [configureVirtualBackground()](/reference/sdk/methods/configurevirtualbackground.md), because the virtual background panel is hidden from the participant, so nobody in the session notices either.

#### Sample payload

```json
{
  "type": "appError",
  "data": {
    "name": "virtual-bg",
    "message": "Virtual background was not applied: this device cannot run virtual backgrounds",
    "data": {
      "reason": "unsupported",
      "virtualBackgroundConfig": {
        "enabled": true,
        "type": "blur",
        "name": "blur-balanced",
        "enforced": true,
        "value": {
          "src": "balanced",
          "thumb": "<thumbnail url>",
          "alt": "<label>"
        }
      }
    }
  }
}
```

`data.virtualBackgroundConfig` describes **the background you requested**, in exactly the same shape as the [virtualBackgroundChanged](/reference/sdk/events/virtualbackgroundchanged.md) event — not the background that is now active. It is the requested configuration precisely because that configuration was *not* applied.

#### `data.reason`

| Value         | Meaning                                                                                                            |
| ------------- | ------------------------------------------------------------------------------------------------------------------ |
| `unsupported` | This device cannot run virtual backgrounds. The request is refused; the participant continues on their raw camera. |
| `failed`      | The device can run virtual backgrounds, but applying this one failed.                                              |

{% hint style="info" %}
**Telling the new events apart from the legacy ones.** `name: "virtual-bg"` is also used for invalid `configureVirtualBackground()` options (an unknown image name, a missing `thumbnailUrl`, and similar). Those carry no `data.reason`. Branch on the presence of `data.reason`, not on the name alone.
{% endhint %}

#### Sample subscription code

```javascript
sambaFrame.on('appError', (event) => {
  const error = event.data; // { name, message, data }

  if (error.name !== 'virtual-bg' || !error.data?.reason) {
    return; // not a "not applied" report — a legacy option-validation error
  }

  if (error.data.reason === 'unsupported') {
    console.warn('This participant cannot run virtual backgrounds — they are on a raw camera.');
  } else {
    console.warn('Applying the virtual background failed.');
  }

  console.log('Requested background was:', error.data.virtualBackgroundConfig);
});
```

#### Timing and how often it fires

{% hint style="warning" %}
Two behaviours worth designing around before you treat this event as a one-shot signal:

* **`unsupported` can arrive up to \~30 seconds after your `configureVirtualBackground()` call, and before the participant has joined.** The room re-probes the device's graphics capability for about 30 seconds before accepting a refusal, because a device that reports no capability at page load frequently recovers within that window. You get one `unsupported` event per `configureVirtualBackground()` command, so a page reload or a second call means another event.
* **`failed` can be reported more than once in a session for the same request.** A configured background is re-attempted when the participant joins, joins a breakout room, and when broadcasting restarts. Each attempt that fails reports its own event. Every one of them is individually true — an activation was attempted and it failed — so treat them as repeated attempts rather than distinct problems, and de-duplicate on your side if you only want to warn the presenter once.
  {% endhint %}

If the background is applied successfully on a later attempt, you receive a normal [virtualBackgroundChanged](/reference/sdk/events/virtualbackgroundchanged.md) event. A `virtual-bg` `appError` is never retracted, so the last VB event you received is always the current truth.
