agalwood/Motrix · error · MediaParseError
unsupported-live
unsupported-live
Error message
live HLS is not supported
What it means
MediaParseError with code 'unsupported-live', thrown by parseHlsMedia when the playlist has neither #EXT-X-ENDLIST nor #EXT-X-PLAYLIST-TYPE:VOD. The library only handles static (complete) HLS media playlists because it builds a fixed SegmentPlan; live/sliding-window playlists require ongoing refresh which it does not model.
Source
Thrown at src/core/media/hls-parser.ts:139
* - METHOD=NONE → clears active key
* - METHOD=SAMPLE-AES/other → MediaParseError('unsupported-encryption')
* - EXT-X-BYTERANGE with running per-resource offset
* - Live guard: no ENDLIST and not PLAYLIST-TYPE:VOD → MediaParseError('unsupported-live')
*/
export function parseHlsMedia(text: string, url: string): SegmentPlan {
const lines = text.split(/\r?\n/)
const hasEndlist = lines.some((l) => l.startsWith('#EXT-X-ENDLIST'))
const playlistType = lines
.find((l) => l.startsWith('#EXT-X-PLAYLIST-TYPE:'))
?.slice('#EXT-X-PLAYLIST-TYPE:'.length)
?.trim()
?.toUpperCase()
const isVod = playlistType === 'VOD'
if (!hasEndlist && !isVod) {
throw new MediaParseError('unsupported-live', 'live HLS is not supported')
}
// Parse MEDIA-SEQUENCE
let seq = 0
const seqLine = lines.find((l) => l.startsWith('#EXT-X-MEDIA-SEQUENCE:'))
if (seqLine) {
seq = Number(seqLine.slice('#EXT-X-MEDIA-SEQUENCE:'.length).trim())
}
// Running state
let activeKey: KeyRef | null = null
let activeInit: InitSegment | undefined
// Per-resource running byte offset (keyed by resolved URL)
const runningOffset = new Map<string, number>()
// Pending BYTERANGE for the next segment
let pendingByteRange: { length: number; offset?: number } | undefined
const segments: MediaPart[] = []View on GitHub (pinned to 1a708ee577)
Solutions
- Point the fetcher at a finished (ENDLIST present) VOD asset URL.
- If you must play live, use a player with native live HLS support (hls.js, AVPlayer, ExoPlayer) instead of this parser.
- Pre-check: if (!text.includes('#EXT-X-ENDLIST') && !/PLAYLIST-TYPE:VOD/i.test(text)) reject as live before calling parseHlsMedia.
- For event streams, wait until recording completes and the ENDLIST is appended, then re-fetch.
Example fix
// before
const plan = parseHlsMedia(text, url)
// after
const isLive = !text.includes('#EXT-X-ENDLIST') && !/#EXT-X-PLAYLIST-TYPE:VOD/i.test(text)
if (isLive) throw new UserFacingError('Live HLS is not supported. Use a VOD URL.')
const plan = parseHlsMedia(text, url) Defensive patterns
Strategy: validation
Validate before calling
function isStaticHls(text: string): boolean {
return text.includes('#EXT-X-ENDLIST') || /#EXT-X-PLAYLIST-TYPE:VOD/i.test(text)
}
if (!isStaticHls(text)) {
throw new Error('Live HLS is not supported; provide a VOD URL.')
} Type guard
function isStaticHls(text: string): boolean {
return text.includes('#EXT-X-ENDLIST') || /#EXT-X-PLAYLIST-TYPE:VOD/i.test(text)
} Try / catch
try {
const plan = parseHlsMedia(text, url)
} catch (e) {
if (e instanceof MediaParseError && e.code === 'unsupported-live') {
// prompt user for a VOD URL
} else throw e
} Prevention
- Pre-check for EXT-X-ENDLIST / PLAYLIST-TYPE:VOD before parsing.
- For event streams, wait until recording completes and re-fetch.
- Maintain an allowlist of known VOD HLS hosts.
When it happens
Trigger: Calling parseHlsMedia on an active live HLS playlist (no EXT-X-ENDLIST, no PLAYLIST-TYPE:VOD). Typical for ongoing event streams, 24/7 linear channels, or playlists where the encoder has not yet written the closing tag.
Common situations: User-supplied live URL; event playlists still being recorded; CDN edge that strips EXT-X-ENDLIST on in-progress assets; testing against Apple's bipbop live samples rather than the VOD ones.
Related errors
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/1a9e22a9e8a0c275.
Report an issue: GitHub.