agalwood/Motrix · error · MediaParseError
unsupported-encryption
unsupported-encryption
Error message
AES-128 key missing URI
What it means
MediaParseError with code 'unsupported-encryption', thrown by parseHlsMedia when a #EXT-X-KEY line has METHOD=AES-128 but no URI attribute. AES-128 keys must be fetched from a URI; an AES-128 declaration without one is malformed and there is no key material to decrypt segments.
Source
Thrown at src/core/media/hls-parser.ts:173
let pendingByteRange: { length: number; offset?: number } | undefined
const segments: MediaPart[] = []
let index = 0
for (let i = 0; i < lines.length; i++) {
const line = lines[i] ?? ''
// EXT-X-KEY
if (line.startsWith('#EXT-X-KEY:')) {
const attrs = line.slice('#EXT-X-KEY:'.length)
const method = attr(attrs, 'METHOD')
if (method === 'NONE') {
activeKey = null
} else if (method === 'AES-128') {
const keyUri = attr(attrs, 'URI')
if (!keyUri)
throw new MediaParseError(
'unsupported-encryption',
'AES-128 key missing URI'
)
const ivAttr = attr(attrs, 'IV')
// IV resolution happens per-segment (for seq-based IV)
// Store a sentinel: if ivAttr is present, store the parsed bytes; else null
const ivBytes: Uint8Array | null = ivAttr ? parseIvHex(ivAttr) : null
// We store the IV on activeKey as a placeholder; per-segment we may override below
// Use a special marker: store ivBytes or the placeholder for seq-based
activeKey = {
method: 'AES-128',
uri: resolveUri(url, keyUri),
// Temporary: will be resolved per-segment; use seqNumberIv(seq) as default
iv: ivBytes ?? seqNumberIv(seq),
_explicit: ivAttr !== undefined,
_ivBytes: ivBytes,
} as KeyRef & { _explicit: boolean; _ivBytes: Uint8Array | null }
} else {View on GitHub (pinned to 1a708ee577)
Solutions
- Inspect the raw playlist and locate the offending #EXT-X-KEY line.
- If the URI was stripped by a proxy/rewriter, fix the rewrite rule to preserve URI=.
- If the manifest is genuinely malformed, fetch an unmodified copy from the origin.
- Pre-validate before parsing: every EXT-X-KEY with METHOD=AES-128 must have a URI attribute.
Example fix
// before — playlist has '#EXT-X-KEY:METHOD=AES-128' const plan = parseHlsMedia(text, url) // after — fix the source manifest line to // '#EXT-X-KEY:METHOD=AES-128,URI="https://cdn.example/key.bin"' const plan = parseHlsMedia(text, url)
Defensive patterns
Strategy: validation
Validate before calling
function aes128KeysHaveUri(text: string): boolean {
return [...text.matchAll(/#EXT-X-KEY:[^\n]+/gi)].every(line => {
const method = /METHOD=([A-Z0-9-]+)/i.exec(line[0])?.[1]
if (method !== 'AES-128') return true
return /URI=/i.test(line[0])
})
}
if (!aes128KeysHaveUri(text)) {
throw new Error('AES-128 EXT-X-KEY is missing URI.')
} Type guard
function aes128KeysHaveUri(text: string): boolean {
return [...text.matchAll(/#EXT-X-KEY:[^\n]+/gi)].every(line => {
const method = /METHOD=([A-Z0-9-]+)/i.exec(line[0])?.[1]
return method !== 'AES-128' || /URI=/i.test(line[0])
})
} Try / catch
try {
const plan = parseHlsMedia(text, url)
} catch (e) {
if (e instanceof MediaParseError && e.code === 'unsupported-encryption' && /missing URI/.test(e.message)) {
// fetch unmodified manifest from origin
} else throw e
} Prevention
- Validate EXT-X-KEY lines before parsing when ingesting third-party manifests.
- Avoid manifest-rewriting proxies that drop attributes.
- Fetch the raw manifest from origin when a key error appears, to rule out proxy mangling.
When it happens
Trigger: An HLS media playlist containing #EXT-X-KEY:METHOD=AES-128 (no URI=...). Caused by a broken encoder/packager, an in-place edit that stripped the URI, or a manifest proxy that rewrote the line incompletely.
Common situations: Custom manifest filter/rewriter that drops attributes; vendor packager bug; test fixtures hand-written without the URI; copy-paste of an EXT-X-KEY template that left METHOD but removed URI.
Related errors
- unsupported-master
- unsupported-encryption
- unsupported-master
- unsupported-live
- Key must be 16 bytes, got ${key.length} from ${uri}
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/98d24c5a8be7a2e8.
Report an issue: GitHub.