---
"@context": https://schema.org
"@type": TechArticle
"@id": https://www.twilio.com/docs/video/media-sdk-troubleshooting#article
headline: Troubleshoot Node.js Media SDK issues
description: Fixes for common issues with the Video Media SDK for Node.js.
url: https://www.twilio.com/docs/video/media-sdk-troubleshooting
inLanguage: en
dateModified: 2026-10-05T15:56:06.000Z
author:
  "@type": Organization
  name: Twilio Developer Education Team
publisher:
  "@type": Organization
  name: Twilio
---

# Troubleshoot Node.js Media SDK issues

> \[!IMPORTANT]
>
> The Video Media SDK for Node.js is currently available as a Public Beta product and the information contained in this document is subject to change. This means that some features are not yet implemented and others may be changed before the product is declared as Generally Available. Public Beta products are not covered by the Twilio Support Terms or [Twilio Service Level Agreement][sla].
>
> The Video Media SDK for Node.js is not a US [*Health Insurance Portability and Accountability Act* (HIPAA)][hipaa] Eligible Service or [*Payment Card Industry Data Security Standard* (PCI DSS)][pci] compliant and should not be enabled in workflows that are subject to HIPAA or PCI.

[hipaa]: https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act

[pci]: https://en.wikipedia.org/wiki/Payment_Card_Industry_Data_Security_Standard

[sla]: https://help.twilio.com/articles/115002413087-Twilio-Beta-product-support

## SDK installation fails on Apple Silicon

On an Apple Silicon Mac with an arm64 version of Node installed, the npm install of this SDK `npm install @twilio/video-node-sdk` fails, returning `npm error code EBADPLATFORM`. To correct this error, switch to an x64 build of Node.js.

The SDK requires an x64 build of Node.js. Rosetta lets an x64 build run on Apple Silicon, but installing Rosetta doesn't change which build of Node.js you have. If your Node.js is an arm64 build, the SDK doesn't install.

To install an x64 build of Node.js on an Apple Silicon (M-series) Mac, follow these steps:

1. In Terminal, install Rosetta:
   ```shell
   /usr/sbin/softwareupdate --install-rosetta --agree-to-license
   ```
2. Install an x64 build of Node.js version 24.0.0 or later. Open a shell that runs under Rosetta, and then install Node.js with nvm:
   ```shell
   arch -x86_64 zsh
   nvm install 24
   ```
3. Confirm that your Node.js install uses the `x64` architecture:
   ```shell
   node -e "console.log(process.arch)"
   ```
   A successful install returns `x64`. If this commands returns `arm64`, you're running an arm64 build:
   * If you have an arm64 build of Node.js 24, remove it, and then repeat steps 2 and 3:
     ```shell
     nvm deactivate
     nvm uninstall 24
     ```

If `npm install` fails with `npm error code EBADPLATFORM` and reports `"cpu":"arm64"`, you're running an arm64 build of Node.js. Follow the preceding steps to switch to an x64 build.

## Unsupported platform error

If the SDK throws an `UnsupportedPlatformError`, there's no prebuilt binary for your platform or architecture. Run the SDK on Linux x86-64, or on macOS x86\_64 for local development, with an x64 build of Node.js version 24.0.0 or later. If you use an Apple Silicon Mac, see [SDK installation fails on Apple Silicon](#sdk-installation-fails-on-apple-silicon).

## Prebuilt binary fails to load

If loading the SDK throws a `NativeBindingLoadError` that says the prebuilt binary failed to load, check your prerequisites:

1. Confirm that you're running Node.js version 24.0.0 or later:
   ```shell
   node --version
   ```
   On earlier versions, npm installs the SDK with only a warning.
2. On macOS, confirm that you're running macOS 26 or later:
   ```shell
   sw_vers -productVersion
   ```
   The prebuilt binary targets macOS 26. npm can't check the operating system version, so on macOS 25 or earlier the install succeeds and the binary fails to load.
3. On Linux, confirm that the `libX11` library is installed:
   ```shell
   ldconfig -p | grep libX11
   ```
   If the command prints nothing, the library is missing. Minimal container images, such as `node:24-slim`, don't include it. On Debian or Ubuntu, install it:
   ```shell
   apt-get update && apt-get install -y libx11-6
   ```
4. On Linux, confirm that glibc is version 2.34 or later:
   ```shell
   ldd --version
   ```
   The first line of the output shows the glibc version. The SDK doesn't support Alpine or other musl-based distributions.

## Access Token or credential errors

If the Access Token is malformed, expired, or missing a Video grant, `connect()` rejects with one of the `AccessToken*Error` classes, such as `AccessTokenInvalidError` (20101) or `AccessTokenExpiredError` (20104). To handle it, wrap `await connect()` in a `try...catch` block, then check the following:

1. [Set environment variables][uid] for `TWILIO_ACCOUNT_SID`, `TWILIO_API_KEY`, and `TWILIO_API_SECRET`.
2. Add a [`VideoGrant`][VideoGrant] to the token.
3. If the token expired, generate a new one.

## Unknown video or audio codec error

If `connect()` rejects with `TypeError: Unknown video codec: <name>` or `TypeError: Unknown audio codec: <name>`, the SDK doesn't support a codec in your connect options. This error can appear when you reuse connect options from the JavaScript SDK, such as `preferredVideoCodecs: ['H264']`.

The SDK accepts the following values:

* `preferredVideoCodecs`: `'VP8'`
* `preferredAudioCodecs`: `'opus'` and `'PCMU'`

Codec names are case-sensitive, so `'vp8'` and `'Opus'` also fail. In TypeScript, the `VideoCodec` and `AudioCodec` types catch unsupported values at compile time. To fix the error, use only the supported values or leave out the option:

```javascript
const room = await connect(token, {
  name: 'my-room',
  preferredVideoCodecs: ['VP8'],
  preferredAudioCodecs: ['opus'],
});
```

To learn more, see [Known issues and limitations][known-issues].

## Video track subscription fails with error 53404

If a remote participant publishes an H.264 video track, the SDK can't subscribe to it. The Room emits `trackSubscriptionFailed` with a `MediaNoSupportedCodecError`, which has error code [53404][]. The SDK supports VP8 video only.

To detect the failure, listen for the event:

```javascript
const { MediaNoSupportedCodecError } = require('@twilio/video-node-sdk');

room.on('trackSubscriptionFailed', (error, publication, participant) => {
  if (error instanceof MediaNoSupportedCodecError) {
    console.warn(`Can't subscribe to ${publication.trackName} from ${participant.identity}: unsupported codec`);
  }
});
```

To fix the failure, set `preferredVideoCodecs: ['VP8']` in the client apps that join the Room. To learn how client SDKs set codec preferences, see [Managing codecs][codec-preferences].

## Process doesn't exit

If your app keeps running after it leaves a Room, the Room still holds its native resources. Call `room.dispose()` when you finish with a Room. The `disconnect()` method leaves the Room but doesn't release those resources. The `disconnected` event is a good place to call `dispose()`:

```javascript
room.on('disconnected', () => {
  room.dispose();
});
```

## Frames don't appear in the Room

Verify the following in your code:

1. Wait for `connect()` to resolve, and then push video frames. The SDK drops any video frames that you write before then.
2. Review the parameters you pass to the Room:
   * Pass [video][vframes] frames in the I420 format, which uses the [Y'UV][] color model. Each of `y`, `u`, and `v` is a plane object with its own `data`, `stride`, `width`, and `height`. Frame `width` and `height` must be even.
     * `Y`: Full-resolution [luminance][luma] at the full frame width and height
     * `U`: Blue-difference [chrominance][] (`Cb`) at half the frame width and height
     * `V`: Red-difference chrominance (`Cr`) at half the frame width and height
   * Set [Audio][aframes] frame input to 48 kHz mono `S16LE` `PCM`.
     * `S`: Use *Signed* positive or negative integer values.
     * `16`: Store *16 bits* (or two bytes) of data per audio sample.
     * `LE`: Use the [*little-endian*][le] method to store data placing the least significant byte in the smallest memory address.
     * `PCM`: Convert data using [*Pulse-code modulation*][pcm]: the raw, uncompressed audio wave data.
3. Check the return value of `write()`. It returns `false` when the SDK drops a frame, and `getWriteStats().framesDropped` counts the drops.

### Diagnose Room and media issues

To inspect a Room's media and connection health beyond your own logs, use [Video Insights][].

If you can't resolve an issue, [contact Twilio Support][tw-support].

[53404]: /docs/api/errors/53404

[aframes]: /docs/video/node-working-with-media-frames#audio-frames

[chrominance]: https://en.wikipedia.org/wiki/Chrominance

[codec-preferences]: /docs/video/managing-codecs#controlling-codecs-client-side-codec-preferences

[known-issues]: /docs/video/node#known-issues-and-limitations

[le]: https://en.wikipedia.org/wiki/Endianness

[luma]: https://en.wikipedia.org/wiki/Luma_\(video\)

[pcm]: https://en.wikipedia.org/wiki/Pulse-code_modulation

[tw-support]: https://help.twilio.com

[uid]: /docs/video/tutorials/user-identity-access-tokens

[vframes]: /docs/video/node-working-with-media-frames#video-frames

[Video Insights]: /docs/video/troubleshooting/insights

[VideoGrant]: /docs/video/tutorials/user-identity-access-tokens#generate-helper-lib

[Y'UV]: https://en.wikipedia.org/wiki/Y%E2%80%B2UV
