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
- Source a clear (unencrypted) version of the asset — many CDNs provide a clear preview or trailer variant.
- If DRM playback is required, use a CDM-capable player (Shaka, dash.js with license server) instead of this parser.
- Pre-scan the manifest for <ContentProtection> and surface a user message before invoking parseDash.
- 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
- Pre-scan manifests for <ContentProtection> before invoking the parser.
- Keep a catalogue of clear vs DRM asset URLs and validate input against it.
- Surface a user-facing message naming DRM so the cause is obvious.
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.