{"record":{"id":"6a59a09b156700b4","repo":"sveltejs/kit","slug":"could-not-deserialize-binary-form-file-offset-tab","errorCode":null,"errorMessage":"Could not deserialize binary form: file offset table too short","messagePattern":"Could not deserialize binary form: file offset table too short","errorType":"exception","errorClass":"SvelteKitError","httpStatus":400,"severity":"error","filePath":"packages/kit/src/runtime/form-utils.js","lineNumber":270,"sourceCode":"\tconst data_length = header_view.getUint32(1, true);\n\tconst file_offsets_length = header_view.getUint16(5, true);\n\n\t// Validation uses embedded binary header fields (data_length, file_offsets_length)\n\t// rather than Content-Length, which proxies/middleboxes may strip or corrupt.\n\t// See: https://github.com/sveltejs/kit/issues/15299\n\n\t// Read the form data\n\tconst data_buffer = await get_buffer(HEADER_BYTES, data_length);\n\tif (!data_buffer) throw deserialize_error('data too short');\n\n\t/** @type {Array<number | undefined>} */\n\tlet file_offsets;\n\t/** @type {number} */\n\tlet files_start_offset;\n\tif (file_offsets_length > 0) {\n\t\t// Read the file offset table\n\t\tconst file_offsets_buffer = await get_buffer(HEADER_BYTES + data_length, file_offsets_length);\n\t\tif (!file_offsets_buffer) throw deserialize_error('file offset table too short');\n\n\t\tconst parsed_offsets = JSON.parse(text_decoder.decode(file_offsets_buffer));\n\n\t\tif (\n\t\t\t!Array.isArray(parsed_offsets) ||\n\t\t\tparsed_offsets.some((n) => typeof n !== 'number' || !Number.isInteger(n) || n < 0)\n\t\t) {\n\t\t\tthrow deserialize_error('invalid file offset table');\n\t\t}\n\n\t\tfile_offsets = /** @type {Array<number>} */ (parsed_offsets);\n\t\tfiles_start_offset = HEADER_BYTES + data_length + file_offsets_length;\n\t}\n\n\t/** @type {Array<{ offset: number, size: number }>} */\n\tconst file_spans = [];\n\tconst [data, meta] = devalue.parse(text_decoder.decode(data_buffer), {\n\t\tFile: ([name, type, size, last_modified, index]) => {","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/sveltejs/kit/blob/03f1687fe612ce3d2d9131139b5b188d9cf90c64/packages/kit/src/runtime/form-utils.js#L252-L288","documentation":"SvelteKit's binary form serialization encodes uploaded files in one blob after a JSON payload, with a separate file offset table describing where each file's bytes start. deserialize_binary_form reads that offset table from the request body; if the remaining bytes are shorter than the table's declared length, it throws this error. It means the incoming request body is truncated, corrupted, or was not produced by SvelteKit's serialize_binary_form.","triggerScenarios":"A POST to a SvelteKit action with enctype multipart/form-data whose body was truncated (proxy/CDN cut it off, client aborted mid-upload), a manually crafted or tampered binary payload with a wrong file-offset-table length in the header, or replaying an old/partial body.","commonSituations":"Reverse proxies or load balancers with short body timeouts dropping large uploads; fetch wrappers that re-serialize the request and mangle the binary framing; malware/scanner tampering; custom middleware consuming part of the request stream before SvelteKit reads it.","solutions":["Verify the upload reaches the server intact: check Content-Length vs received bytes and any proxy body-size/timeout limits.","Ensure the request is POSTed by SvelteKit's own form submission code (use: enhance, native form POST) rather than hand-built fetch calls.","Remove middleware that consumes or rewrites the request body before SvelteKit deserializes it.","Retry the upload; if reproducible, log the payload length and header bytes to confirm corruption source."],"exampleFix":"// before: custom fetch that strips body framing\nfetch(actionUrl, { method: 'POST', body: JSON.stringify({ data }) });\n// after: let SvelteKit serialize the form\nimport { enhance } from '$app/forms';\n<form method=\"POST\" use:enhance>","handlingStrategy":"validation","validationCode":"// client side, before sending\nconst body = await request.clone().arrayBuffer();\nif (body.byteLength < expectedHeaderBytes) throw new Error('truncated form payload');","typeGuard":null,"tryCatchPattern":"try {\n  await deserialize_binary_form(request);\n} catch (e) {\n  if (String(e.message).includes('file offset table too short')) {\n    return new Response('Corrupted upload, please retry', { status: 400 });\n  }\n  throw e;\n}","preventionTips":["Use SvelteKit's use:enhance or native form POST, never hand-built fetch bodies.","Check proxy/CDN body size and timeout limits for large uploads.","Don't add middleware that consumes the request stream before the framework.","Monitor Content-Length vs received bytes server-side to detect truncation."],"tags":["sveltekit","forms","serialization","request-body"],"backgroundTag":"binary-payload-corruption","analyzedSha":"03f1687fe612ce3d2d9131139b5b188d9cf90c64","analyzedAt":"2026-09-02T02:01:50.504Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}