{"record":{"id":"4aaea77c8c7b1bbe","repo":"agalwood/Motrix","slug":"unsupported-encryption","errorCode":"unsupported-encryption","errorMessage":"DRM-protected MPD","messagePattern":"DRM-protected MPD","errorType":"error_code","errorClass":"MediaParseError","httpStatus":null,"severity":"error","filePath":"src/core/media/dash-parser.ts","lineNumber":18,"sourceCode":"import {\n  type ByteRange,\n  type InitSegment,\n  MediaParseError,\n  type MediaPart,\n  resolveUri,\n  type SegmentPlan,\n} from './segment-plan'\n\nexport function parseDash(\n  xml: string,\n  mpdUrl: string\n): { video: SegmentPlan; audio?: SegmentPlan } {\n  if (/<MPD\\b[^>]*\\btype\\s*=\\s*\"dynamic\"/i.test(xml)) {\n    throw new MediaParseError('unsupported-live', 'dynamic (live) MPD')\n  }\n  if (/<ContentProtection\\b/i.test(xml)) {\n    throw new MediaParseError('unsupported-encryption', 'DRM-protected MPD')\n  }\n\n  const mpdBaseUrl = extractMpdBaseUrl(xml, mpdUrl)\n\n  const periodMatch = /<Period\\b([^>]*)>([\\s\\S]*?)<\\/Period>/i.exec(xml)\n  const periodAttrs = periodMatch?.[1] ?? ''\n  const periodBody = periodMatch?.[2] ?? xml\n\n  const mpdDuration = parseDuration(\n    attrVal(/<MPD\\b[^>]*>/i.exec(xml)?.[0] ?? '', 'mediaPresentationDuration')\n  )\n  const periodDuration =\n    parseDuration(attrVal(periodAttrs, 'duration')) ?? mpdDuration\n  const periodBaseUrl = resolveLevelBaseUrl(periodBody, mpdBaseUrl)\n\n  const adaptationSets = extractAdaptationSets(periodBody)\n\n  const videoSets = adaptationSets.filter((a) => isMediaType(a.attrs, 'video'))","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/media/dash-parser.ts#L1-L36","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst plan = parseDash(xml, mpdUrl)\n// after\nif (/<ContentProtection\\b/i.test(xml)) {\n  throw new UserFacingError('DRM-protected content is not supported.')\n}\nconst plan = parseDash(xml, mpdUrl)","handlingStrategy":"validation","validationCode":"function isClearMpd(xml: string): boolean {\n  return !/<ContentProtection\\b/i.test(xml)\n}\nif (!isClearMpd(xml)) {\n  throw new Error('DRM-protected DASH is not supported; provide a clear asset.')\n}","typeGuard":"function isClearMpd(xml: string): boolean {\n  return !/<ContentProtection\\b/i.test(xml)\n}","tryCatchPattern":"try {\n  const plan = parseDash(xml, mpdUrl)\n} catch (e) {\n  if (e instanceof MediaParseError && e.code === 'unsupported-encryption') {\n    // route to a DRM-capable player or reject\n  } else throw e\n}","preventionTips":["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."],"tags":["dash","media","drm","encryption","streaming"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}