{"record":{"id":"06abc673aef97d58","repo":"remotion-dev/remotion","slug":"expected-box-size-of-bytesremaining-got-boxs","errorCode":null,"errorMessage":"Expected box size of ${bytesRemaining}, got ${boxSizeRaw}. Incomplete boxes are not allowed.","messagePattern":"Expected box size of (.+?), got (.+?)\\. Incomplete boxes are not allowed\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-parser/src/containers/iso-base-media/process-box.ts","lineNumber":114,"sourceCode":"\tconst boxSizeRaw = iterator.getFourByteNumber();\n\n\tif (boxSizeRaw === 0) {\n\t\treturn {\n\t\t\ttype: 'box',\n\t\t\tbox: {\n\t\t\t\ttype: 'void-box',\n\t\t\t\tboxSize: 0,\n\t\t\t},\n\t\t};\n\t}\n\n\t// If `boxSize === 1`, the 8 bytes after the box type are the size of the box.\n\tif (\n\t\t(boxSizeRaw === 1 && iterator.bytesRemaining() < 12) ||\n\t\titerator.bytesRemaining() < 4\n\t) {\n\t\titerator.counter.decrement(iterator.counter.getOffset() - fileOffset);\n\t\tthrow new Error(\n\t\t\t`Expected box size of ${bytesRemaining}, got ${boxSizeRaw}. Incomplete boxes are not allowed.`,\n\t\t);\n\t}\n\n\tconst maxSize = contentLength - startOff;\n\tconst boxType = iterator.getByteString(4, false);\n\tconst boxSizeUnlimited =\n\t\tboxSizeRaw === 1 ? iterator.getEightByteNumber() : boxSizeRaw;\n\tconst boxSize = Math.min(boxSizeUnlimited, maxSize);\n\tconst headerLength = iterator.counter.getOffset() - startOff;\n\n\tif (boxType === 'mdat') {\n\t\tif (!onlyIfMdatAtomExpected) {\n\t\t\treturn {type: 'nothing'};\n\t\t}\n\n\t\tconst {mediaSectionState} = onlyIfMdatAtomExpected;\n\t\tmediaSectionState.addMediaSection({","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/containers/iso-base-media/process-box.ts#L96-L132","documentation":"Thrown early in processBox() while reading the box header. After reading the 4-byte boxSizeRaw, there are not enough bytes remaining to read the 4-byte box type (or, when boxSizeRaw===1, the 12 bytes needed for an extended 8-byte size). ISO Base Media forbids incomplete boxes, so the parser rewinds and aborts rather than read past the buffer.","triggerScenarios":"parseMedia({src}) when the file/stream is truncated mid-box-header, or when a corrupt boxSizeRaw points beyond the available bytes. Most commonly: an incomplete HTTP download, a truncated local file, a partial range request, or a file whose last box header is only partially present.","commonSituations":"Truncated downloads (server dropped the connection, range request returned fewer bytes), incomplete file writes, partial fragmented segments, or corrupted size fields that overshoot EOF.","solutions":["Verify the source is complete: for HTTP, check Content-Length vs bytes actually received; for local files, confirm the file size matches the original.","Re-download/re-fetch the full file before parsing.","If using a custom reader/range requests, ensure it returns the full byte range the parser requests (the parser issues makeFetchMoreData requests).","Validate integrity (e.g. md5/sha256 against the source) before parsing.","Migrate to @remotion/mediabunny (parseMedia is deprecated)."],"exampleFix":"// before\nconst data = await fetch(url).then((r) => r.arrayBuffer());\nawait parseMedia({src: new Uint8Array(data), reader: webReader});\n\n// after\nconst res = await fetch(url);\nif (!res.ok || Number(res.headers.get('content-length')) > data.byteLength) {\n  throw new Error('Incomplete download — refuse to parse a truncated file');\n}\nconst data = await res.arrayBuffer();\nawait parseMedia({src: new Uint8Array(data), reader: webReader});","handlingStrategy":"validation","validationCode":"// The cause is almost always a truncated/incomplete source. Verify the byte\n// length matches the declared size before parsing.\nasync function assertFullyDownloaded(url: string): Promise<Uint8Array> {\n  const res = await fetch(url);\n  if (!res.ok) throw new Error(`HTTP ${res.status}`);\n  const expected = Number(res.headers.get('content-length'));\n  const buf = new Uint8Array(await res.arrayBuffer());\n  if (Number.isFinite(expected) && buf.byteLength !== expected) {\n    throw new Error(`Truncated download: got ${buf.byteLength} of ${expected} bytes`);\n  }\n  return buf;\n}\n// For local files, compare against a known-good size or checksum:\n//   stat.size === expectedSize  (or sha256 matches)","typeGuard":"// A File/Uint8Array can be narrowed only by size, not by box completeness:\nfunction isLikelyCompleteMp4Header(bytes: Uint8Array): boolean {\n  // an MP4 needs at least 8 bytes for the first box header (size + type)\n  return bytes.byteLength >= 8;\n}","tryCatchPattern":"try {\n  await parseMedia({src, reader: webReader});\n} catch (err) {\n  if (err instanceof Error && /Incomplete boxes are not allowed/.test(err.message)) {\n    // file/stream is truncated mid-box: re-fetch the complete source\n  } else {\n    throw err;\n  }\n}","preventionTips":["Verify Content-Length against bytes received for every HTTP source.","For local files, confirm size/checksum against the original before parsing.","Ensure custom readers serve the full byte range the parser requests (it issues fetch-more-data).","Never parse partial range requests as if they were whole files.","Migrate to @remotion/mediabunny (parseMedia is deprecated)."],"tags":["mp4","iso-base-media","media-parser","truncated","corrupt-file","incomplete-download","box-header"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}