-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Describe the bug
When using remote form() functions, some users intermittently receive a 400 error:
Could not deserialize binary form: data too short
The error originates from @sveltejs/kit/src/runtime/form-utils.js in deserialize_binary_form, specifically line 246 where get_buffer() returns null because the request body stream ends before all expected bytes (based on Content-Length) have been read.
The issue is intermittent and user-dependent — it does not reproduce on localhost, and not all users are affected. This suggests a middlebox (reverse proxy / load balancer) is modifying the request body or its headers in transit.
This worked fine when hosted on Vercel, but started occurring after migrating to Azure App Service (Linux, adapter-node).
Switching from a remote form() to a traditional form action (+page.server.ts with use:enhance from $app/forms) resolves the issue entirely, since standard form submissions use application/x-www-form-urlencoded / multipart/form-data which middleboxes handle correctly.
Root cause analysis
The deserialize_binary_form function uses a custom binary protocol with content type application/x-sveltekit-formdata. It relies on the Content-Length header as the source of truth for validation:
const content_length = parseInt(request.headers.get('content-length') ?? '');Azure App Service is known to modify request bodies in certain conditions — for example, decompressing Content-Encoding: gzip payloads without updating Content-Length (Azure/azure-functions-core-tools#2185), and stripping Content-Type headers from empty POST bodies (Azure/static-web-apps#1512).
When the actual body bytes don't match what Content-Length promises — because a proxy layer re-encoded, decompressed, or truncated the body — get_buffer() runs out of data and returns null, triggering the "data too short" error.
Possible solution
Rather than trusting Content-Length as the sole source of truth, deserialize_binary_form could:
- Read the actual stream length and validate against that instead of (or in addition to) the
Content-Lengthheader. - Validate based on the embedded header length fields — the binary format already contains
data_length(u32) andfile_offsets_length(u16) in the first 7 bytes. These could be used to determine expected size independently ofContent-Length. - Consider using a standard content type (e.g.
multipart/form-data) as a fallback or default, since non-standard content types are more susceptible to middlebox interference.
Reproduction
Hard to reproduce locally. Occurs in production on Azure App Service (Linux) with adapter-node. Does not occur on Vercel.
Logs
System Info
System:
OS: Windows 11 10.0.26200
CPU: (16) x64 AMD Ryzen 7 5800H with Radeon Graphics
Memory: 6.19 GB / 31.36 GB
Binaries:
Node: 22.16.0 - C:\Program Files\nodejs\node.EXE
npm: 11.6.2 - C:\Program Files\nodejs\npm.CMD
pnpm: 8.5.0 - C:\Users\olive\AppData\Roaming\npm\pnpm.CMD
Deno: 1.28.3 - C:\Users\olive\.deno\bin\deno.EXE
Browsers:
Chrome: 144.0.7559.134
Edge: Chromium (141.0.3537.71)
Firefox: 107.0.1 - C:\Program Files\Mozilla Firefox\firefox.exe
Internet Explorer: 11.0.26100.7309
npmPackages:
@sveltejs/adapter-auto: ^7.0.0 => 7.0.0
@sveltejs/adapter-node: ^5.4.0 => 5.4.0
@sveltejs/adapter-vercel: ^5.6.3 => 5.6.3
@sveltejs/kit: ^2.50.2 => 2.50.2
@sveltejs/vite-plugin-svelte: ^6.2.3 => 6.2.3
svelte: ^5.49.1 => 5.49.1
vite: ^6.2.1 => 6.4.1Severity
serious, but I can work around it
Additional Information
This is a production issue that affects end users intermittently, with no client-side workaround other than migrating away from remote form() functions to traditional form actions.
I got help from Claude Code to generate this issue, since I had no idea how to pinpoint the problem, so I hope the information is enough!