Skip to content

GuidePlayback

Handle playback errors

Display playback failures, report them, and choose a useful recovery action.

Display playback failures instead of leaving a dead player, report the failure when you need diagnostics, and give users a useful next step.

Render a <media-error-dialog> inside the player container. It reads error state, presents the failure, and dismisses cleanly. The prebuilt skins include one.

<video-player>
  <media-container>
    <video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" muted playsinline></video>
    <media-error-dialog>
      <media-dialog-popup>
        <media-dialog-title></media-dialog-title>
        <media-dialog-description></media-dialog-description>
        <media-dialog-close></media-dialog-close>
      </media-dialog-popup>
    </media-error-dialog>
  </media-container>
</video-player>
<script type="module">
  import '@videojs/html/video/player';
  import '@videojs/html/ui/container';
  import '@videojs/html/ui/error-dialog';
  import '@videojs/html/ui/dialog-popup';
  import '@videojs/html/ui/dialog-title';
  import '@videojs/html/ui/dialog-description';
  import '@videojs/html/ui/dialog-close';
</script>

The dialog renders its text into the child parts — a title, the error description, and a dismiss button — and fills each empty part with default copy. Write your own text inside a part to replace the default. Without the child parts, the dialog opens with nothing to show.

How it works

The error feature mirrors the media element’s error into player state:

  • error holds the media’s error — code, message — or null when there is none.
  • dismissError() clears the error from player state (the media element keeps its own error until a new load).
  • Loading a new source resets error to null automatically.

The dialog owns presentation, not recovery. Decide the next step in your application: let the user dismiss the message, choose another item, refresh an expired URL, or contact support.

Availability and constraints

  • For a terminal failure, load a new or refreshed source to recover. An aborted load or an adapter-specific error may have different behavior.
  • Standard media error codes distinguish broad classes — aborted, network, decode, and source-not-supported — rather than root causes. A media adapter can report its own numeric code too.
  • Streaming engines handle recoverable segment and network failures before surfacing a terminal error. Do not layer a generic same-source retry loop on top of the engine.
  • Once the player attaches to the media element, errors land in state even before any UI renders (bad URL at mount); make sure your error surface renders regardless of playback state.

Common variations

Offer an application-specific next step

Use the error code and your product context to choose the action. A live event can link to its status page, an authenticated app can refresh an expired playback URL, and a playlist can offer the next item. Keep that action outside <media-error-dialog>; the dialog can close after your application has handled it.

Report errors to monitoring

Subscribe to error state and forward new errors to your monitoring service with the source URL and error.code. A media error does not automatically appear in JavaScript exception monitoring.

Subscribe after the player element has registered. Compare the current error with the previous one because the store also notifies for unrelated state changes:

import '@videojs/html/video/player';
import { selectError } from '@videojs/html';

const player = document.querySelector('video-player');
if (!player) throw new Error('Missing video-player');

let previousError: { code: number; message: string } | null = null;

function reportNewError() {
  const error = selectError(player.store.state)?.error ?? null;
  if (error === previousError) return;

  previousError = error;
  if (error) console.error('Playback failed', error.code, error.message);
}

const unsubscribe = player.store.subscribe(reportNewError);
reportNewError();
// Call unsubscribe() when this player is removed.

Replace the console.error call with your monitoring service and include the current source URL.

Diagnose a reported failure

Start with error.code and the affected source URL. Check the browser’s network panel for failed media requests, response status, redirects, CORS headers, and expired credentials. If requests succeed, check the file’s container and codecs against the chosen media component. For HLS or DASH, inspect the streaming engine’s diagnostics for segment and manifest failures; the player error often names only the final outcome.

Troubleshooting

The player is black and silent with no error

Not every dead player is a media error — autoplay blocking and an unset source produce no error. Check error, source, and paused in player state to tell them apart. If play() rejects with NotAllowedError, see Autoplay.

A VJS8_LEGACY_* exception appears

These codes identify Video.js 8 APIs used with the Video.js 10 video.js package. Look up the code in the error code reference for its trigger and v10 equivalent. The player error state covered in this guide receives media playback errors after setup.

Error code says the source isn’t supported

The browser can’t play the format through this media element. HLS in a plain video element outside Safari is the classic case; use the matching streaming media element. See Media sources.

Reopening the source produces the same error

The failure is probably permanent for that source, such as a 404, revoked token, unsupported codec, or CORS response. Fix or replace the source instead of repeatedly loading the same URL.

Components

API

Guides