remotion-dev/remotion · error · MediaPlaybackError
The browser threw an error while playing the video ${props.s
Error message
The browser threw an error while playing the video ${props.src}: Code ${current.error.code} - ${current?.error?.message}. See https://remotion.dev/docs/media-playback-error for help. Pass an onError() prop to handle the error. What it means
In the server-render path of `<Video>`, when the underlying video element emits an `error` event with a populated `current.error` and the caller did not supply `onError`, Remotion throws a `MediaPlaybackError` with the browser code, message, the offending `src`, and a docs link.
Source
Thrown at packages/core/src/video/VideoForRendering.tsx:234
});
seek.prom.then(() => {
continueRender(handle);
});
current.addEventListener('ended', endedHandler, {once: true});
const errorHandler = () => {
if (current?.error) {
// eslint-disable-next-line no-console
console.error('Error occurred in video', current?.error);
// If user is handling the error, we don't cause an unhandled exception
if (onError) {
return;
}
throw new MediaPlaybackError({
message: `The browser threw an error while playing the video ${props.src}: Code ${current.error.code} - ${current?.error?.message}. See https://remotion.dev/docs/media-playback-error for help. Pass an onError() prop to handle the error.`,
src: props.src as string,
});
} else {
throw new MediaPlaybackError({
message: 'The browser threw an error',
src: props.src as string,
});
}
};
current.addEventListener('error', errorHandler, {once: true});
// If video skips to another frame or unmounts, we clear the created handle
return () => {
seek.cancel();
current.removeEventListener('ended', endedHandler);
current.removeEventListener('error', errorHandler);View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Add an `onError` prop to `<Video>` so the render can capture the failure.
- Re-encode the asset to faststart H.264 MP4 with AAC audio.
- Ensure the asset URL is reachable from the render environment (Lambda, Docker, etc.).
- Increase `delayRenderTimeoutInMilliseconds` if the asset is large but loadable.
Example fix
// before
<Video src={url} />
// after
<Video src={url} onError={(err) => console.error(err)} delayRenderTimeoutInMilliseconds={30000} /> Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-validate asset reachability from the render host
const res = await fetch(src, {method: 'HEAD'});
if (!res.ok) throw new Error(`Asset unreachable from render host: ${res.status}`); Type guard
const isFaststartMp4 = async (url: string): Promise<boolean> => { /* probe moov atom position */ return true; }; Try / catch
<Video
src={url}
delayRenderTimeoutInMilliseconds={30000}
onError={(err) => {
// capture but don't abort the render
logRenderError(err);
}}
/> Prevention
- Always pass `onError` to `<Video>` in renderable compositions.
- Encode source assets as faststart H.264 MP4 with AAC audio.
- Verify asset URLs are reachable from Lambda/Docker render hosts.
- Raise `delayRenderTimeoutInMilliseconds` for large assets.
When it happens
Trigger: Server-rendering a composition that contains `<Video>` whose asset fails to load or decode in the headless Chrome used by the renderer, with no `onError` handler on the component.
Common situations: Codec unsupported by the render Chrome (e.g. HEVC, ProRes), inaccessible URL from the render host, large asset failing on slow disk, or non-faststart MP4 forcing the renderer to time out and emit an error.
Related errors
- The browser threw an error while playing the video ${src}: C
- The browser threw an error
- The codec is not a video codec
- WebGL context was lost during canvas effect rendering. This
- No WebGPU adapter available
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/ec4c0c245a6d3347.
Report an issue: GitHub.