Skip to content

Remote form binary deserialization fails intermittently on Azure App Service ("data too short") #15299

@oliie

Description

@oliie

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:

  1. Read the actual stream length and validate against that instead of (or in addition to) the Content-Length header.
  2. Validate based on the embedded header length fields — the binary format already contains data_length (u32) and file_offsets_length (u16) in the first 7 bytes. These could be used to determine expected size independently of Content-Length.
  3. 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.1

Severity

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions