Docs
Player ReactError handling

Error handling

Typed errors, the inline unavailable surface, the error boundary, and retry.

The web player handles two distinct failure classes:

  • Playback errors (access denied, not found, network, etc.): surfaced as a typed error from the hook, rendered inline as an unavailable surface.
  • Unexpected render crashes: caught by a MoviieErrorBoundary so they never take down the host app.

Inline unavailable surface

<MoviieVideo> renders an inline unavailable surface automatically: no extra setup. When useMoviiePlayer resolves an error, the component shows a viewer-facing title and description, plus a Try again button for retryable errors. This mirrors the gated and error states the iframe embed shows.

const moviie = useMoviiePlayer({ embedId })

// the unavailable surface renders automatically when moviie.error is set
return <MoviieVideo {...moviie} aspectRatio={16 / 9} />

Typed errors

Each error carries a code and maps to a typed class exported from @moviie/player-sdk (re-exported by @moviie/player-react).

CodeClassWhen it occursRetryable
authMoviieAuthErrorInvalid or missing publishable key (mvi_pub_*).
playback_tokenMoviiePlaybackTokenErrorA private video needs a valid viewer token.
not_foundMoviieNotFoundErrorThe embed ID does not exist or was removed.
bundle_blockedMoviieBundleBlockedErrorThe client is not in the embed's allowlist.
referrer_blockedMoviieReferrerBlockedErrorThe request origin is not in the embed's referrer allowlist.
direct_access_blockedMoviieDirectAccessBlockedErrorThe video was opened directly by URL while that is blocked.
web_distribution_blockedMoviieWebDistributionBlockedErrorWeb playback is not enabled for this video.
video_not_readyMoviieVideoNotReadyErrorThe video is still processing.
subscription_inactiveMoviieSubscriptionInactiveErrorThe organization's subscription is paused or expired.
insufficient_creditsMoviieInsufficientCreditsErrorA feature is temporarily unavailable for this organization.
networkMoviieNetworkErrorThe request failed (timeout, unreachable, etc.).
rate_limitMoviieRateLimitErrorToo many requests in a short period.
unknownError (fallback)Any unrecognized error.

Reading and detecting errors

useMoviiePlayer (and useMoviiePlayback) expose error and isLoading:

const { error, isLoading, playback } = useMoviiePlayer({ embedId })

if (error) {
  console.log(error.code)    // e.g. "bundle_blocked"
  console.log(error.message) // human-readable message
}

Match by class or by code:

import {
  MoviieAuthError,
  MoviieBundleBlockedError,
  MoviieNetworkError,
} from "@moviie/player-react"

if (error instanceof MoviieAuthError) {
  // invalid key: check your publishable key
}

if (error instanceof MoviieNetworkError) {
  // transient: a retry is appropriate
}

if (error?.code === "referrer_blocked") {
  // configure the embed's allowed referrers in the dashboard
}

Custom unavailable UI

To render your own surface instead of the built-in one, branch on error yourself. resolveUnavailableSurface returns the same per-code title, description, and canRetry flag the player uses:

import { resolveUnavailableSurface, useMoviiePlayer } from "@moviie/player-react"

function Player({ embedId }: { embedId: string }) {
  const moviie = useMoviiePlayer({ embedId })

  if (moviie.error) {
    const surface = resolveUnavailableSurface(moviie.error)
    return (
      <div role="alert">
        <h2>{surface.title}</h2>
        <p>{surface.description}</p>
        {surface.canRetry && <button onClick={moviie.retry}>Try again</button>}
      </div>
    )
  }

  return <MoviieVideo {...moviie} aspectRatio={16 / 9} />
}

errorCodeOf(error) is also exported if you only need the resolved code.

Retry

For retryable errors, the inline surface's Try again button calls moviie.retry(), which re-triggers the playback fetch. You can call retry yourself from custom UI (as above) or after invalidating your own cache.

<MoviieErrorBoundary>

<MoviieVideo> already wraps itself in a MoviieErrorBoundary, so an unexpected render crash shows a styled fallback instead of breaking your app. Wire your reporter with onError:

<MoviieVideo {...moviie} onError={(error, info) => Sentry.captureException(error)} />

Use the boundary directly to protect a larger tree or to supply a custom fallback:

import { MoviieErrorBoundary, MoviieVideo } from "@moviie/player-react"

<MoviieErrorBoundary
  onError={(error) => Sentry.captureException(error)}
  fallback={({ error, reset }) => (
    <div role="alert">
      <p>The player ran into a problem.</p>
      <button onClick={reset}>Reload</button>
    </div>
  )}
>
  <MoviieVideo {...moviie} aspectRatio={16 / 9} />
</MoviieErrorBoundary>

The library never reports for you

@moviie/player-react surfaces errors to the host app and never initializes a reporter (such as Sentry) itself. Wire onError to your own pipeline.

On this page