{"record":{"id":"60203ce511a11185","repo":"remotion-dev/remotion","slug":"unexpected-end-of-file","errorCode":null,"errorMessage":"Unexpected end of file","messagePattern":"Unexpected end of file","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-parser/src/containers/m3u/parse-m3u-manifest.ts","lineNumber":18,"sourceCode":"import type {BufferIterator} from '../../iterator/buffer-iterator';\nimport type {ParseResult} from '../../parse-result';\nimport {parseM3u8Text} from './parse-m3u8-text';\nimport type {M3uStructure} from './types';\n\nexport const parseM3uManifest = ({\n\titerator,\n\tstructure,\n\tcontentLength,\n}: {\n\titerator: BufferIterator;\n\tstructure: M3uStructure;\n\tcontentLength: number;\n}): Promise<ParseResult> => {\n\tconst start = iterator.startCheckpoint();\n\tconst line = iterator.readUntilLineEnd();\n\tif (iterator.counter.getOffset() > contentLength) {\n\t\tthrow new Error('Unexpected end of file');\n\t}\n\n\tif (line === null) {\n\t\tstart.returnToCheckpoint();\n\t\treturn Promise.resolve(null);\n\t}\n\n\tparseM3u8Text(line.trim(), structure.boxes);\n\n\treturn Promise.resolve(null);\n};\n","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/containers/m3u/parse-m3u-manifest.ts#L1-L30","documentation":"Thrown by parseM3uManifest() at parse-m3u-manifest.ts:18 when, after reading a line via iterator.readUntilLineEnd(), the iterator's byte offset exceeds the declared contentLength. This means the byte stream ended mid-line — the manifest data was truncated or contentLength was set to a value smaller than the actual data read.","triggerScenarios":"The HTTP response body was cut short (connection dropped, proxy timeout, partial cache); contentLength was computed incorrectly (e.g., from a wrong Content-Length header); or the reader returned fewer bytes than expected but the iterator advanced past the boundary.","commonSituations":"Network timeout during manifest download; CDN or reverse proxy truncating large manifests; incorrect Content-Length header from the origin server; file read interrupted by process abort.","solutions":["Retry the fetch to rule out transient network truncation","Verify the Content-Length header matches the actual response body size","Check for intermediate proxies or load balancers that may truncate large responses"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Verify the response is complete before parsing\nconst resp = await fetch(url);\nconst text = await resp.text();\nif (text.trim() === '' || !resp.ok) {\n  throw new Error('Manifest response is empty or failed');\n}\nconst contentLength = Number(resp.headers.get('content-length') ?? text.length);\nif (text.length < contentLength) {\n  throw new Error('Manifest response was truncated');\n}\nawait parseMedia({src: url});","typeGuard":null,"tryCatchPattern":"async function parseWithRetry(src: string, retries = 3) {\n  for (let i = 0; i <= retries; i++) {\n    try {\n      return await parseMedia({src});\n    } catch (e) {\n      if (e instanceof Error && e.message === 'Unexpected end of file' && i < retries) continue;\n      throw e;\n    }\n  }\n}","preventionTips":["Retry on truncation errors as they are often caused by transient network issues","Verify Content-Length headers match actual response sizes from your CDN","Check for proxies or load balancers that may truncate large manifest responses"],"tags":["hls","m3u8","truncated","network","content-length"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}