sveltejs/kit · error · SvelteKitError

Could not deserialize binary form: file offset table too sho

Error message

Could not deserialize binary form: file offset table too short

What it means

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.

Source

Thrown at packages/kit/src/runtime/form-utils.js:270

	const data_length = header_view.getUint32(1, true);
	const file_offsets_length = header_view.getUint16(5, true);

	// Validation uses embedded binary header fields (data_length, file_offsets_length)
	// rather than Content-Length, which proxies/middleboxes may strip or corrupt.
	// See: https://github.com/sveltejs/kit/issues/15299

	// Read the form data
	const data_buffer = await get_buffer(HEADER_BYTES, data_length);
	if (!data_buffer) throw deserialize_error('data too short');

	/** @type {Array<number | undefined>} */
	let file_offsets;
	/** @type {number} */
	let files_start_offset;
	if (file_offsets_length > 0) {
		// Read the file offset table
		const file_offsets_buffer = await get_buffer(HEADER_BYTES + data_length, file_offsets_length);
		if (!file_offsets_buffer) throw deserialize_error('file offset table too short');

		const parsed_offsets = JSON.parse(text_decoder.decode(file_offsets_buffer));

		if (
			!Array.isArray(parsed_offsets) ||
			parsed_offsets.some((n) => typeof n !== 'number' || !Number.isInteger(n) || n < 0)
		) {
			throw deserialize_error('invalid file offset table');
		}

		file_offsets = /** @type {Array<number>} */ (parsed_offsets);
		files_start_offset = HEADER_BYTES + data_length + file_offsets_length;
	}

	/** @type {Array<{ offset: number, size: number }>} */
	const file_spans = [];
	const [data, meta] = devalue.parse(text_decoder.decode(data_buffer), {
		File: ([name, type, size, last_modified, index]) => {

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Verify the upload reaches the server intact: check Content-Length vs received bytes and any proxy body-size/timeout limits.
  2. Ensure the request is POSTed by SvelteKit's own form submission code (use: enhance, native form POST) rather than hand-built fetch calls.
  3. Remove middleware that consumes or rewrites the request body before SvelteKit deserializes it.
  4. Retry the upload; if reproducible, log the payload length and header bytes to confirm corruption source.

Example fix

// before: custom fetch that strips body framing
fetch(actionUrl, { method: 'POST', body: JSON.stringify({ data }) });
// after: let SvelteKit serialize the form
import { enhance } from '$app/forms';
<form method="POST" use:enhance>
Defensive patterns

Strategy: validation

Validate before calling

// client side, before sending
const body = await request.clone().arrayBuffer();
if (body.byteLength < expectedHeaderBytes) throw new Error('truncated form payload');

Try / catch

try {
  await deserialize_binary_form(request);
} catch (e) {
  if (String(e.message).includes('file offset table too short')) {
    return new Response('Corrupted upload, please retry', { status: 400 });
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02). Data as JSON: /api/errors/6a59a09b156700b4. Report an issue: GitHub.