agalwood/Motrix · error · MediaParseError
unsupported-master
unsupported-master
Error message
no video representation
What it means
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.
Source
Thrown at src/core/media/dash-parser.ts:40
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'))
const audioSets = adaptationSets.filter((a) => isMediaType(a.attrs, 'audio'))
if (videoSets.length === 0) {
throw new MediaParseError('unsupported-master', 'no video representation')
}
const video = pickBestPlan(videoSets, periodBaseUrl, periodDuration, mpdUrl)
if (video === null) {
throw new MediaParseError('unsupported-master', 'no video representation')
}
let audio: SegmentPlan | undefined
if (audioSets.length > 0) {
const audioPlan = pickBestPlan(
audioSets,
periodBaseUrl,
periodDuration,
mpdUrl
)
if (audioPlan !== null) {
audio = audioPlan
}View on GitHub (pinned to 1a708ee577)
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.
Example fix
// before
const { video } = parseDash(xml, mpdUrl)
// after — verify a video set exists and is classifiable
const hasVideoSet = /<AdaptationSet\b[^>]*\b(?:contentType|mimeType)\s*=\s*"video/i.test(xml)
if (!hasVideoSet) throw new UserFacingError('No video track in this DASH manifest.')
const { video } = parseDash(xml, mpdUrl) Defensive patterns
Strategy: validation
Validate before calling
function dashHasVideoSet(xml: string): boolean {
return /<AdaptationSet\b[^>]*\b(?:contentType|mimeType)\s*=\s*"video/i.test(xml)
}
if (!dashHasVideoSet(xml)) {
throw new Error('No video AdaptationSet found in this DASH manifest.')
} Type guard
function dashHasVideoSet(xml: string): boolean {
return /<AdaptationSet\b[^>]*\b(?:contentType|mimeType)\s*=\s*"video/i.test(xml)
} Try / catch
try {
const { video } = parseDash(xml, mpdUrl)
} catch (e) {
if (e instanceof MediaParseError && e.code === 'unsupported-master') {
// classify as 'no playable video track' for the user
} else throw e
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/d0ec5d8668098556.
Report an issue: GitHub.