{"record":{"id":"d0ec5d8668098556","repo":"agalwood/Motrix","slug":"unsupported-master","errorCode":"unsupported-master","errorMessage":"no video representation","messagePattern":"no video representation","errorType":"error_code","errorClass":"MediaParseError","httpStatus":null,"severity":"error","filePath":"src/core/media/dash-parser.ts","lineNumber":40,"sourceCode":"\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'))\n  const audioSets = adaptationSets.filter((a) => isMediaType(a.attrs, 'audio'))\n\n  if (videoSets.length === 0) {\n    throw new MediaParseError('unsupported-master', 'no video representation')\n  }\n\n  const video = pickBestPlan(videoSets, periodBaseUrl, periodDuration, mpdUrl)\n  if (video === null) {\n    throw new MediaParseError('unsupported-master', 'no video representation')\n  }\n\n  let audio: SegmentPlan | undefined\n  if (audioSets.length > 0) {\n    const audioPlan = pickBestPlan(\n      audioSets,\n      periodBaseUrl,\n      periodDuration,\n      mpdUrl\n    )\n    if (audioPlan !== null) {\n      audio = audioPlan\n    }","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/media/dash-parser.ts#L22-L58","documentation":"MediaParseError with code 'unsupported-master', thrown by parseDash at line 40 when zero AdaptationSets in the Period are classified as video (by contentType or mimeType starting with 'video'). The parser requires at least one video AdaptationSet to produce a SegmentPlan.","triggerScenarios":"Calling parseDash on a manifest whose AdaptationSets are all audio-only (e.g. a pure-audio DASH pack), whose video sets lack contentType/mimeType attributes (so the regex classifier misses them), or whose Period body failed to match the <Period>...</Period> regex entirely.","commonSituations":"Audio-only podcast assets; manifests that rely on <Codecs> attributes instead of explicit contentType/mimeType; deeply nested or malformed Periods where the greedy regex returns empty; misidentified media type because the AdaptationSet uses mimeType=\"video/mp4\" vs contentType that the parser does not see.","solutions":["Inspect the manifest and confirm at least one AdaptationSet has contentType=\"video\" or mimeType starting with \"video\".","If the asset is audio-only, route it to an audio-only pipeline rather than parseDash's video expectation.","Pre-check the manifest: const hasVideo = /<AdaptationSet[^>]*\\bcontentType\\s*=\\s*\"video\"/i.test(xml).","If the manifest uses codec-based typing, patch isMediaType or pre-process the XML to add contentType attributes."],"exampleFix":"// before\nconst { video } = parseDash(xml, mpdUrl)\n// after — verify a video set exists and is classifiable\nconst hasVideoSet = /<AdaptationSet\\b[^>]*\\b(?:contentType|mimeType)\\s*=\\s*\"video/i.test(xml)\nif (!hasVideoSet) throw new UserFacingError('No video track in this DASH manifest.')\nconst { video } = parseDash(xml, mpdUrl)","handlingStrategy":"validation","validationCode":"function dashHasVideoSet(xml: string): boolean {\n  return /<AdaptationSet\\b[^>]*\\b(?:contentType|mimeType)\\s*=\\s*\"video/i.test(xml)\n}\nif (!dashHasVideoSet(xml)) {\n  throw new Error('No video AdaptationSet found in this DASH manifest.')\n}","typeGuard":"function dashHasVideoSet(xml: string): boolean {\n  return /<AdaptationSet\\b[^>]*\\b(?:contentType|mimeType)\\s*=\\s*\"video/i.test(xml)\n}","tryCatchPattern":"try {\n  const { video } = parseDash(xml, mpdUrl)\n} catch (e) {\n  if (e instanceof MediaParseError && e.code === 'unsupported-master') {\n    // classify as 'no playable video track' for the user\n  } else throw e\n}","preventionTips":["Before parsing, regex-check the manifest for a video-typed AdaptationSet.","For audio-only assets, route to an audio-only pipeline rather than parseDash.","When a packager emits codec-only typing, normalise the manifest to add contentType before parsing."],"tags":["dash","media","streaming","validation"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}