sveltejs/kit · error · SvelteKitError

Could not deserialize binary form: duplicate file offset tab

Error message

Could not deserialize binary form: duplicate file offset table index

What it means

Each entry in the binary form's file offset table must be used by exactly one file's metadata 'index'. deserialize_binary_form marks each offset as used (sets it to undefined); if a second file references the same index, or an index is out of range, it throws this error to block duplicated or aliased file references.

Source

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

	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');
			}

			let offset = file_offsets[index];

			// Check that the file offset table entry has not been already
			// used. If not, immediately mark it as used.
			if (offset === undefined) {
				throw deserialize_error('duplicate file offset table index');
			}
			file_offsets[index] = undefined;

			offset += files_start_offset;

			file_spans.push({ offset, size });

			return new Proxy(new LazyFile(name, type, size, last_modified, get_chunk, offset), {
				getPrototypeOf() {
					// Trick validators into thinking this is a normal File
					return File.prototype;
				}
			});
		}
	});

	// Sort file spans in increasing order primarily by offset
	// and secondarily by size (to allow 0-length files).

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Submit forms through SvelteKit's standard flow so indexes are generated correctly.
  2. Match client/server @sveltejs/kit versions.
  3. Reject malformed requests at proxy/WAF level if you're under attack.
  4. Clear caches/redeploy if a stale mismatched client bundle is in circulation.

Example fix

// before: reusing an index in custom serialization
meta.files = [{ name: 'a', index: 0 }, { name: 'b', index: 0 }];
// after: unique index per file
meta.files = [{ name: 'a', index: 0 }, { name: 'b', index: 1 }];
Defensive patterns

Strategy: validation

Validate before calling

const seen = new Set();
for (const f of meta.files) {
  if (seen.has(f.index)) throw new Error('duplicate file index ' + f.index);
  seen.add(f.index);
}

Type guard

function hasUniqueIndexes(files) {
  const seen = new Set();
  return files.every((f) => !seen.has(f.index) && seen.add(f.index) !== undefined);
}

Try / catch

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

Prevention

When it happens

Trigger: A multipart/form-data action request where two file entries share the same offset-table index, or where an index is >= the table length — from corrupted payloads, hand-crafted requests, or serializer/format mismatches.

Common situations: Fuzzing or deliberate tampering with action endpoints; middleware that rewrites the JSON section; version-skewed client/server binaries producing inconsistent index tables.

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/bccd21d2221dfe18. Report an issue: GitHub.