Videos SDK
Guides

Errors

One typed error across every provider — a VideoError with a discriminated code.

Every provider fails differently — different status codes, different response shapes, different SDKs. Videos SDK collapses all of that into one error type: a VideoError with a discriminated code. You write your error handling once and it holds no matter which adapter is underneath.

The shape

VideoError extends the native Error, so instanceof, stack traces, and the cause chain all work as usual. On top of that it carries:

class VideoError extends Error {
  code: VideoErrorCode;      // discriminated — switch on this
  provider?: string;         // "rehelios" | "mux" | "bunny" | "cloudflare"
  status?: number;           // upstream HTTP status, when there was one
  cause?: unknown;           // the original provider error
}

Codes

codeWhen it happens
unauthorizedBad or missing credentials (HTTP 401 / 403).
not_foundThe asset doesn't exist (HTTP 404).
unsupported_operationThe provider can't do this — also a compile error.
upload_failedThe bytes didn't make it to the provider.
rate_limitedToo many requests (HTTP 429). Back off and retry.
provider_errorThe provider returned something unexpected (usually 5xx).
networkThe request never completed (DNS, timeout, offline).
invalid_requestBad arguments before any request went out.

Handling it

Narrow on code — it's a string literal union, so the compiler checks your branches:

import { VideoError } from 'videos-sdk';

try {
  return await videos.get(id);
} catch (error) {
  if (!(error instanceof VideoError)) throw error;

  switch (error.code) {
    case 'not_found':
      return null; // treat a missing asset as empty
    case 'unauthorized':
      throw new Error('Check your provider credentials');
    default:
      throw error; // anything else bubbles up
  }
}

Retrying rate limits

rate_limited and transient network / provider_error failures are the ones worth retrying. Everything else is a bug in your call, not a blip:

async function withRetry<T>(fn: () => Promise<T>, tries = 3): Promise<T> {
  for (let attempt = 1; ; attempt++) {
    try {
      return await fn();
    } catch (error) {
      const retryable =
        error instanceof VideoError &&
        (error.code === 'rate_limited' || error.code === 'network');
      if (!retryable || attempt >= tries) throw error;
      await new Promise((r) => setTimeout(r, 2 ** attempt * 250));
    }
  }
}

const asset = await withRetry(() => videos.get(id));

unsupported_operation almost never reaches runtime — the capability types stop you from calling an operation a provider doesn't support at compile time. You only hit it if you force a call through a cast.

On this page