agalwood/Motrix · error
Key must be 16 bytes, got ${key.length} from ${uri}
Error message
Key must be 16 bytes, got ${key.length} from ${uri} What it means
Plain Error thrown inside SegmentDecryptor's default key fetcher when the bytes downloaded from the key URI are not exactly 16 bytes long. AES-128 keys are definitionally 128 bits = 16 bytes; any other length means the URI did not return a key (HTML error page, wrong content, truncated response). The message includes both the actual length and the offending URI.
Source
Thrown at src/core/media/segment-decryptor.ts:19
import { createDecipheriv } from 'node:crypto'
export class SegmentDecryptor {
private keyCache: Map<string, Promise<Uint8Array>>
private defaultFetchKey: (uri: string) => Promise<Uint8Array>
constructor(fetchKey?: (uri: string) => Promise<Uint8Array>) {
this.keyCache = new Map()
if (fetchKey) {
this.defaultFetchKey = fetchKey
} else {
this.defaultFetchKey = async (uri: string) => {
const response = await fetch(uri)
const buffer = await response.arrayBuffer()
const key = new Uint8Array(buffer)
if (key.length !== 16) {
throw new Error(`Key must be 16 bytes, got ${key.length} from ${uri}`)
}
return key
}
}
}
decrypt(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array): Uint8Array {
// Validate key and IV lengths
if (key.length !== 16) {
throw new Error(`Key must be 16 bytes, got ${key.length}`)
}
if (iv.length !== 16) {
throw new Error(`IV must be 16 bytes, got ${iv.length}`)
}
// Convert Uint8Array to Buffer for crypto operations
const keyBuffer = Buffer.from(key)
const ivBuffer = Buffer.from(iv)View on GitHub (pinned to 1a708ee577)
Solutions
- Fetch the key URI directly with curl and inspect the byte length and content type.
- Confirm the EXT-X-KEY URI in the manifest resolves to a raw 16-byte octet stream.
- If the key endpoint returns base64/hex, supply a custom fetchKey to SegmentDecryptor that decodes before returning.
- Check response.status before reading the body — a 404 returning HTML is the usual culprit.
Example fix
// before
const decryptor = new SegmentDecryptor()
// after — custom fetcher that validates status and decodes base64 keys
const decryptor = new SegmentDecryptor(async (uri) => {
const res = await fetch(uri)
if (!res.ok) throw new Error(`key fetch failed: HTTP ${res.status}`)
const raw = await res.text()
const buf = Buffer.from(raw.trim(), 'base64')
if (buf.length !== 16) throw new Error(`bad key length ${buf.length}`)
return new Uint8Array(buf)
}) Defensive patterns
Strategy: try-catch
Validate before calling
async function fetchAes128Key(uri: string): Promise<Uint8Array> {
const res = await fetch(uri)
if (!res.ok) throw new Error(`key HTTP ${res.status}`)
const buf = new Uint8Array(await res.arrayBuffer())
if (buf.length !== 16) throw new Error(`key at ${uri} is ${buf.length} bytes, not 16`)
return buf
}
const decryptor = new SegmentDecryptor(fetchAes128Key) Try / catch
try {
const key = await decryptor.getKey(keyUri)
} catch (e) {
if (/Key must be 16 bytes.*from/.test(String(e))) {
// re-fetch the key URI manually to inspect; likely a 404 HTML page
} else throw e
} Prevention
- Provide a custom fetchKey to SegmentDecryptor that checks res.ok and content type before reading the body.
- Confirm EXT-X-KEY URIs resolve to raw 16-byte octet streams by curling them once during integration.
- Handle base64/hex-encoded key endpoints by decoding in the custom fetcher.
When it happens
Trigger: getKey(uri) or defaultFetchKey(uri) where the fetched resource is not a raw 16-byte AES key — e.g. the URI returns a 404 HTML page (200–5000 bytes), a JSON error object, a binary key of the wrong size (24/32 bytes for AES-192/256), or an empty response.
Common situations: Expired key URL returning an error page; CORS/proxy injecting HTML; key endpoint migrated to return base64-encoded keys (which are ~24 bytes); wrong key URI resolved from a malformed EXT-X-KEY line; TLS/cert page interception.
Related errors
- unsupported-encryption
- Key must be 16 bytes, got ${key.length}
- IV must be 16 bytes, got ${iv.length}
- transient-failure
- unsupported-encryption
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/5fbb340ee76ae45c.
Report an issue: GitHub.