{"record":{"id":"d2375009e38504de","repo":"remotion-dev/remotion","slug":"ext-x-version-directive-must-have-a-value","errorCode":null,"errorMessage":"EXT-X-VERSION directive must have a value","messagePattern":"EXT-X-VERSION directive must have a value","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-parser/src/containers/m3u/parse-directive.ts","lineNumber":15,"sourceCode":"import {\n\tparseM3uKeyValue,\n\tparseM3uMediaDirective,\n} from './parse-m3u-media-directive';\nimport {parseStreamInf} from './parse-stream-inf';\nimport type {M3uBox} from './types';\n\nexport const parseM3uDirective = (str: string): M3uBox => {\n\tconst firstColon = str.indexOf(':');\n\tconst directive = (firstColon === -1 ? str : str.slice(0, firstColon)).trim();\n\tconst value = firstColon === -1 ? null : str.slice(firstColon + 1);\n\n\tif (directive === '#EXT-X-VERSION') {\n\t\tif (!value) {\n\t\t\tthrow new Error('EXT-X-VERSION directive must have a value');\n\t\t}\n\n\t\treturn {\n\t\t\ttype: 'm3u-version',\n\t\t\tversion: value,\n\t\t};\n\t}\n\n\tif (directive === '#EXT-X-INDEPENDENT-SEGMENTS') {\n\t\treturn {\n\t\t\ttype: 'm3u-independent-segments',\n\t\t};\n\t}\n\n\tif (directive === '#EXT-X-MEDIA') {\n\t\tif (!value) {\n\t\t\tthrow new Error('EXT-X-MEDIA directive must have a value');\n\t\t}","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/containers/m3u/parse-directive.ts#L1-L33","documentation":"Thrown by parseM3uDirective() at parse-directive.ts:15 when a line is identified as #EXT-X-VERSION but has no value after the colon separator. Per RFC 8216 the #EXT-X-VERSION directive is optional but if present must carry a numeric protocol version. The parser splits on the first colon; if none exists or the value after it is empty/falsy, it throws.","triggerScenarios":"A playlist line '#EXT-X-VERSION' with no colon and version number, or '#EXT-X-VERSION:' with an empty value after the colon.","commonSituations":"Hand-edited m3u8 files where the version number was accidentally deleted; corrupted manifest from a buggy encoder or packager; playlist truncated right after the directive name.","solutions":["Ensure the directive includes a numeric version: #EXT-X-VERSION:3","Regenerate the playlist with a compliant HLS packager (FFmpeg, MediaConvert, Shaka)","Fix the line manually if editing the playlist source"],"exampleFix":"// before\n#EXT-X-VERSION\n\n// after\n#EXT-X-VERSION:3","handlingStrategy":"validation","validationCode":"// Pre-fetch the m3u8 and check #EXT-X-VERSION has a value\nconst text = await (await fetch(url)).text();\nfor (const line of text.split('\\n')) {\n  if (line.trim() === '#EXT-X-VERSION' || line.trim() === '#EXT-X-VERSION:') {\n    throw new Error('#EXT-X-VERSION is missing its numeric value');\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await parseMedia({src: url});\n} catch (e) {\n  if (e instanceof Error && e.message.includes('EXT-X-VERSION')) {\n    // fix the playlist source or regenerate with a compliant packager\n  }\n  throw e;\n}","preventionTips":["Use a compliant HLS packager (FFmpeg, MediaConvert, Shaka) to generate playlists","Validate generated playlists with an HLS conformance checker before deployment"],"tags":["hls","m3u8","directive","ext-x-version","malformed"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}