agalwood/Motrix · error · MediaParseError

unsupported-encryption

unsupported-encryption

Error message

DRM-protected MPD

What it means

MediaParseError with code 'unsupported-encryption', thrown by parseDash when the manifest contains a <ContentProtection> element. The parser has no DRM/ClearKey CDM integration and refuses encrypted manifests rather than producing unplayable segment plans.

Source

Thrown at src/core/media/dash-parser.ts:18

import {
  type ByteRange,
  type InitSegment,
  MediaParseError,
  type MediaPart,
  resolveUri,
  type SegmentPlan,
} from './segment-plan'

export function parseDash(
  xml: string,
  mpdUrl: string
): { video: SegmentPlan; audio?: SegmentPlan } {
  if (/<MPD\b[^>]*\btype\s*=\s*"dynamic"/i.test(xml)) {
    throw new MediaParseError('unsupported-live', 'dynamic (live) MPD')
  }
  if (/<ContentProtection\b/i.test(xml)) {
    throw new MediaParseError('unsupported-encryption', 'DRM-protected MPD')
  }

  const mpdBaseUrl = extractMpdBaseUrl(xml, mpdUrl)

  const periodMatch = /<Period\b([^>]*)>([\s\S]*?)<\/Period>/i.exec(xml)
  const periodAttrs = periodMatch?.[1] ?? ''
  const periodBody = periodMatch?.[2] ?? xml

  const mpdDuration = parseDuration(
    attrVal(/<MPD\b[^>]*>/i.exec(xml)?.[0] ?? '', 'mediaPresentationDuration')
  )
  const periodDuration =
    parseDuration(attrVal(periodAttrs, 'duration')) ?? mpdDuration
  const periodBaseUrl = resolveLevelBaseUrl(periodBody, mpdBaseUrl)

  const adaptationSets = extractAdaptationSets(periodBody)

  const videoSets = adaptationSets.filter((a) => isMediaType(a.attrs, 'video'))

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Source a clear (unencrypted) version of the asset — many CDNs provide a clear preview or trailer variant.
  2. If DRM playback is required, use a CDM-capable player (Shaka, dash.js with license server) instead of this parser.
  3. Pre-scan the manifest for <ContentProtection> and surface a user message before invoking parseDash.
  4. Verify you are not accidentally hitting a geo-fenced encrypted edge server.

Example fix

// before
const plan = parseDash(xml, mpdUrl)
// after
if (/<ContentProtection\b/i.test(xml)) {
  throw new UserFacingError('DRM-protected content is not supported.')
}
const plan = parseDash(xml, mpdUrl)
Defensive patterns

Strategy: validation

Validate before calling

function isClearMpd(xml: string): boolean {
  return !/<ContentProtection\b/i.test(xml)
}
if (!isClearMpd(xml)) {
  throw new Error('DRM-protected DASH is not supported; provide a clear asset.')
}

Type guard

function isClearMpd(xml: string): boolean {
  return !/<ContentProtection\b/i.test(xml)
}

Try / catch

try {
  const plan = parseDash(xml, mpdUrl)
} catch (e) {
  if (e instanceof MediaParseError && e.code === 'unsupported-encryption') {
    // route to a DRM-capable player or reject
  } else throw e
}

Prevention

When it happens

Trigger: Calling parseDash on a Widevine, PlayReady, or ClearKey-protected MPD — any commercial streaming asset (Netflix-style, major-studio) where ContentProtection descriptors are present inside AdaptationSets.

Common situations: Premium content URLs handed to a tool that only handles clear streams; test fixtures from encrypted-content packs; studio CDN endpoints that apply DRM by default.

Related errors


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/4aaea77c8c7b1bbe. Report an issue: GitHub.