{"record":{"id":"142ed69cfb156c57","repo":"remotion-dev/remotion","slug":"expected-m3u-text-value-142ed6","errorCode":null,"errorMessage":"Expected m3u-text-value","messagePattern":"Expected m3u-text-value","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-parser/src/containers/m3u/get-streams.ts","lineNumber":63,"sourceCode":"\toriginalSrc,\n\treaderInterface,\n}: {\n\tstructure: MediaParserStructureUnstable | null;\n\toriginalSrc: ParseMediaSrc;\n\treaderInterface: MediaParserReaderInterface;\n}): M3uStream[] | null => {\n\tif (structure === null || structure.type !== 'm3u') {\n\t\treturn null;\n\t}\n\n\tconst boxes: Omit<M3uStream, 'id'>[] = [];\n\n\tfor (let i = 0; i < structure.boxes.length; i++) {\n\t\tconst str = structure.boxes[i];\n\t\tif (str.type === 'm3u-stream-info') {\n\t\t\tconst next = structure.boxes[i + 1];\n\t\t\tif (next.type !== 'm3u-text-value') {\n\t\t\t\tthrow new Error('Expected m3u-text-value');\n\t\t\t}\n\n\t\t\tconst associatedPlaylists: M3uAssociatedPlaylist[] = [];\n\n\t\t\tif (str.audio) {\n\t\t\t\tconst match = structure.boxes.filter((box) => {\n\t\t\t\t\treturn box.type === 'm3u-media-info' && box.groupId === str.audio;\n\t\t\t\t}) as M3uMediaInfo[];\n\n\t\t\t\tfor (const audioTrack of match) {\n\t\t\t\t\tassociatedPlaylists.push({\n\t\t\t\t\t\tautoselect: audioTrack.autoselect,\n\t\t\t\t\t\tchannels: audioTrack.channels,\n\t\t\t\t\t\tdefault: audioTrack.default,\n\t\t\t\t\t\tgroupId: audioTrack.groupId,\n\t\t\t\t\t\tlanguage: audioTrack.language,\n\t\t\t\t\t\tname: audioTrack.name,\n\t\t\t\t\t\tsrc: readerInterface.createAdjacentFileSource(","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/containers/m3u/get-streams.ts#L45-L81","documentation":"Thrown by getM3uStreams() at get-streams.ts:63 while iterating a master playlist's boxes. When it encounters an m3u-stream-info box (from #EXT-X-STREAM-INF), it reads the next box expecting it to be an m3u-text-value containing the variant's media playlist URI. If the next box is any other type or is missing (end of array), the master playlist structure is invalid.","triggerScenarios":"A master playlist where #EXT-X-STREAM-INF is the last line with no URI following it; a directive appearing between #EXT-X-STREAM-INF and its URI; a truncated master playlist where the response was cut off after the STREAM-INF line.","commonSituations":"Truncated HTTP response fetching the master manifest (network timeout, proxy); hand-edited m3u8 with misplaced directives; CDN serving partial content due to range-request issues.","solutions":["Verify the master playlist has a media playlist URI on the line immediately after each #EXT-X-STREAM-INF","Check for network truncation of the manifest response and retry","Validate the master playlist structure with an HLS conformance checker"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-fetch the master playlist and verify each EXT-X-STREAM-INF has a following URI\nconst text = await (await fetch(masterUrl)).text();\nconst lines = text.split('\\n');\nfor (let i = 0; i < lines.length; i++) {\n  if (lines[i].startsWith('#EXT-X-STREAM-INF')) {\n    if (i + 1 >= lines.length || !lines[i + 1].trim() || lines[i + 1].startsWith('#')) {\n      throw new Error('Master playlist STREAM-INF without a following URI');\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await parseMedia({src: masterUrl});\n} catch (e) {\n  if (e instanceof Error && e.message === 'Expected m3u-text-value') {\n    // master playlist is malformed or truncated\n  }\n  throw e;\n}","preventionTips":["Retry on truncation errors as they are often transient","Validate master playlists from third-party CDNs before relying on them"],"tags":["hls","m3u8","master-playlist","truncated","ext-x-stream-inf"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}