sveltejs/kit · error · SvelteKitError

Could not deserialize binary form: invalid file offset table

Error message

Could not deserialize binary form: invalid file offset table

What it means

The file offset table read from a binary form payload must be a JSON array of non-negative integers. deserialize_binary_form throws this when the table parses but fails that shape check. This guards against malformed or tampered payloads that would otherwise cause arbitrary file slicing later.

Source

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

	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]) => {
			if (
				typeof name !== 'string' ||
				typeof type !== 'string' ||
				typeof size !== 'number' ||
				typeof last_modified !== 'number' ||
				typeof index !== 'number'
			) {
				throw deserialize_error('invalid file metadata');

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Ensure client and server run the same @sveltejs/kit version so the binary format matches.
  2. Submit the form through SvelteKit's normal flow (native POST or use:enhance) so serialization is canonical.
  3. Check intermediaries (proxies, WAFs, virus scanners) that could rewrite the body.
  4. Log and reject the offending request at the edge if you're seeing deliberate tampering.

Example fix

// before: hand-rolling the payload
const body = new Blob([JSON.stringify({ offsets: [-1, 'x'] })]);
// after: use the library's serializer output unchanged
await fetch(actionUrl, { method: 'POST', body: kitSerializedFormData });
Defensive patterns

Strategy: validation

Validate before calling

const offsets = parsed?.fileOffsets;
const valid = Array.isArray(offsets) && offsets.every((n) => typeof n === 'number' && Number.isInteger(n) && n >= 0);

Type guard

function isValidOffsetTable(v) {
  return Array.isArray(v) && v.every((n) => typeof n === 'number' && Number.isInteger(n) && n >= 0);
}

Try / catch

try {
  await deserialize_binary_form(request);
} catch (e) {
  if (String(e.message).includes('invalid file offset table')) {
    return new Response('Malformed request', { status: 400 });
  }
  throw e;
}

Prevention

When it happens

Trigger: A multipart/form-data action request whose binary payload contains an offset table that is not an array (e.g. an object or string) or contains negative/non-integer/non-number entries — typically from a hand-crafted request, corrupted transfer, or wrong serializer version on the client.

Common situations: Proxy or antivirus rewriting the body; client and server on mismatched SvelteKit versions with different binary framing; security scanners fuzzing action endpoints; manual replay of captured requests with edited content.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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