> ## Content Index
> Fetch the complete content index at: https://blog.addpipe.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# MediaRecorder Error Handling: Lessons from Millions of Browser Recordings
- URL: https://blog.addpipe.com/mediarecorder-error-handling/
- Published: 2026-04-02T17:57:18.000Z
- Updated: 2026-05-21T07:58:12.000Z
- Author: Alexandru
- Tags: MediaStream Recording API, getUserMedia, getDisplayMedia, #Import 2026-05-22 13:18

If you've spent any time building a browser-based video or audio recording solution on top of the [MediaStream Recording API](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream%5FRecording%5FAPI) and it's [MediaRecorder](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder) object, you already know that getting a stream from `getUserMedia()` or `getDisplayMedia()` is only half the battle. The other half is dealing with everything that can go wrong once you actually try to record it.

At [Pipe](https://addpipe.com/video-recorder/), we've been running a browser-based [recording client](https://addpipe.com/recording-client/) in production for years, handling audio recording, video recording, and screen capture across a huge range of devices, browsers, and operating systems. We've processed millions of recordings created through the MediaStream Recording API. As a result, we've hit pretty much every possible `MediaRecorder` error. Some of them are obvious, some are hard to deal with.

This article covers the six errors we've encountered, what they actually mean in practice, and how to handle them.

## A quick note on where these errors surface

Unlike [getUserMedia() errors](https://blog.addpipe.com/common-getusermedia-errors/), which are thrown synchronously as rejected promises, `MediaRecorder` errors can show up in two different places depending on when they occur:

- Errors thrown at **construction** (`new MediaRecorder(stream, options)`) behave like regular exceptions, they propagate immediately.
- Errors thrown at **`start()`** or during an **active recording session** are delivered asynchronously via the `onerror` event (or `addEventListener('error', ...)`).

That distinction matters a lot for how you structure your error handling, and it's where many bugs can arise.

## The errors

### 1\. InvalidStateError

**What it means:** You called `MediaRecorder.start()` while the recorder was already running or paused.

This one is almost always a code bug rather than a user or environment problem. It happens when you call `start()` twice without stopping in between, or if you're not tracking the recorder state carefully enough and hit a race condition. For example, a button click handler fires before a previous recording session has fully stopped.

The [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/start#invalidstateerror) are pretty clear on this: `start()` must only be called when the recorder is in the `inactive` state. You can check `mediaRecorder.state` before calling it, which should return `"inactive"`, `"recording"`, or `"paused"`.

```javascript
if (mediaRecorder.state === "inactive") {
    mediaRecorder.start();
} else {
    console.warn("Recorder is already active:", mediaRecorder.state);
}

```

**In practice**, we saw this most often with edge cases in our UI, such as rapid double-clicks on a record button or situations where a stop-and-restart sequence doesn't wait for the onstop callback to fire before calling start() again. Guard your start() calls carefully.

### 2\. SecurityError

**What it means:** The `MediaStream` being recorded is configured to disallow recording.

It's conceptually the MediaRecorder-side sibling of [getUserMedia()'s NotAllowedError](https://blog.addpipe.com/common-getusermedia-errors/). The difference is *when* it surfaces: `NotAllowedError` fires when you're trying to get the stream; `SecurityError` fires when you're trying to record it.

The [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/start#securityerror) also note it can arrive as an `error` event mid-recording if security conditions change after recording has already started, for example, if a track's source changes in a way that makes it non-recordable.

**In practice**, we can replicate this on Chrome with an iframe with the `sandbox` attribute set (Chrome will log `SecurityError Invalid security origin` to the console). There's no automatic recovery possible. We show a descriptive error message inside our recording client and ask the user to check their browser permissions.

### 3\. NotSupportedError

**What it means:** This one can come from two completely different situations, and that's what makes it tricky.

- **At construction:** if you pass a `mimeType` to `new MediaRecorder(stream, { mimeType: "video/mp4; codecs=h264" })` that the browser doesn't support, it throws a `NotSupportedError` immediately. You're supposed to check `MediaRecorder.isTypeSupported(mimeType)` before constructing, but that only tells you whether the browser *claims* to support it (more on that when we get to `EncodingError`).
- **At `start()`** : if the `MediaStream` being recorded is inactive, or if one or more of its tracks can't be recorded with the current configuration, you get a `NotSupportedError` at start time instead.

It's worth noting that a document-level `NotSupportedError` from `getUserMedia()` , thrown when the browser itself doesn't support the API, uses the exact same error name, which adds to the confusion.

[MDN constructor reference](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/MediaRecorder#notsupportederror) | [MDN start() reference](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/start#notsupportederror)

**In practice:** A `NotSupportedError` at construction due to an unsupported MIME type is really the same class of problem as `EncodingError` . The codec doesn't work, but it surfaces earlier and with a different error name. We treat them similarly: fall back to a known-good codec. The key difference is that `NotSupportedError` at construction is at least "*honest*"*.* The browser is telling you upfront it can't do it. `EncodingError` (and a separate class of `NotSupportedError`) hits you when you start recording.

### 4\. InvalidModificationError

**What it means:** The track composition of the `MediaStream` changed while recording was active. A track was added or removed dynamically from the stream. The MediaRecorder doesn't support this, it locks in the stream's track structure when recording starts.

Per the [spec](https://www.w3.org/TR/mediastream-recording/#dom-mediarecordererrorevent), this will be surfaced as an `error` event on the recorder.

**In practice:** This is fairly uncommon in straightforward recording scenarios, but it can happen if you're doing more advanced stream manipulation, for example, dynamically switching between camera inputs by adding and removing tracks from a stream, or mixing streams from multiple sources. The fix is to stop the recorder, modify the stream, and start a new `MediaRecorder` instance with the updated stream rather than trying to modify the stream while the recorder is running.

### 5\. EncodingError

**What it means:** The recorder accepted your codec configuration, passed the `isTypeSupported()` check, constructed without errors, and then failed at runtime when actual media frames started coming in. The hardware or software encoder can't handle the codec, resolution, or bitrate you asked for.

This is the most painful MediaRecorder error we've dealt with, because `isTypeSupported()` gives you a false positive. The browser *thinks* it can encode this, but the actual encoder disagrees once it sees real data.

Per the [spec](https://www.w3.org/TR/mediastream-recording/#dom-mediarecordererrorevent), it's listed as a possible error name in the `onerror` event. In practice, Chrome delivers it with one of a few specific error messages:

- `"Video encoding failed."` : the older Chrome message
- `"Encoder initialization failed."` : typically seen during screen recording
- `"The given encoder configuration is not supported by the encoder."` : the newer Chrome message

We've hit this error twice in recent times. The first time was during cross-device testing on an older **Samsung Galaxy A8 running Android 9**. We were trying to record video with H.264, `isTypeSupported()` came back `true`, but as soon as we called `start()` the recorder threw an `EncodingError`. No H.264 support, despite the browser claiming otherwise through `isTypeSupported`.

The second time was when we tested 5k screen recording with `getDisplayMedia()` on an **M4 Mac Mini** and on a **13 inch M1 MacBook** (both connected to a 5k monitor). Everything worked fine at normal resolutions, but on a 5k display the encoder would silently fail to initialize and throw `EncodingError` right at the start of recording.

**Our solution:** We implemented an automatic codec fallback in our recording client. We listen for `EncodingError` and check the error message against the known Chrome strings above. If it matches, and we haven't already fallen back, we switch to VP8 and retry. Without this retry mechanism, a large number of devices will silently fail to record video using H.264, and you'll have no idea why. The behavior depends on whether any data has already been recorded:

- **If no data was captured yet** (the error hit at initialization, before any frames were encoded): we suppress the normal stop handler, reset state back to idle, and immediately call `start()` again with VP8\. The user barely notices anything happened.
- **If data was already recorded** (the encoder failed mid-session): we stop the recording gracefully and save what we have, rather than discarding it. Restarting mid-session with a different codec would produce an incompatible file, so a clean stop is the right call here.

The VP8 fallback covers the vast majority of cases. If we're already on VP8 and still getting an encoding error, we fall through to showing the user an error message. At that point something more fundamental is wrong.

The `EncodingError` fallback: Checking for those specific Chrome error message strings is the most important piece of custom logic here. 

### 6\. UnknownError

**What it means:** Something went wrong that doesn't fit any of the other categories and isn't security-related. The spec's catch-all. Per the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/error%5Fevent#unknownerror), it's reserved for errors that are genuinely unclassifiable.

**In practice:** We've seen this very rarely, and when we have, it's been impossible to reproduce reliably. It tends to appear on unusual device/browser combinations where the browser itself seems to be having a bad day. There's no meaningful recovery you can implement for a true `UnknownError` . The best you can do is surface a clear message to the user and log as much context as possible (device, browser, OS, media constraints, mimeType) so you can investigate.

## Handling all of these in code

You can setup error handling for all six errors in your code. The key is listening on the `onerror` event for runtime errors, and wrapping the `MediaRecorder` constructor in a try/catch for errors that surface at construction.

[Our audio, video and screen recording client](https://addpipe.com/recording-client/) already does it.

## Summary

| Error                    | When it surfaces                    | Recovery possible?                      |
| ------------------------ | ----------------------------------- | --------------------------------------- |
| InvalidStateError        | start() called in wrong state       | Yes: guard start() calls                |
| SecurityError            | Stream not allowed to be recorded   | No: surface to user                     |
| NotSupportedError        | Construction or start()             | Sometimes: fall back to supported codec |
| InvalidModificationError | Mid-recording, stream track changed | Yes: stop, modify stream, restart       |
| EncodingError            | Mid-recording, encoder failure      | Often: fall back to VP8                 |
| UnknownError             | Anytime                             | No: log and surface to user             |

Most of these errors you can handle gracefully with a combination of defensive coding and a good fallback codec strategy. The spec defines them clearly, but browser behavior, especially around `EncodingError` and the false positives from `isTypeSupported()` , doesn't always match the theory. **Test on real devices, especially older Android phones and high-resolution displays, and don't trust `isTypeSupported()` as your only safety net.**

If you'd rather not deal with any of this yourself, the Pipe recording client bundles with the [Pipe Platform](https://addpipe.com/) handles it for you, including the codec fallback, cross-browser normalization, and error recovery, so your users just get a recorder that works.