File uploads fixed in HTTP Request node
Multipart form-data file uploads should now complete successfully in production n8n deployments, where binary streams previously caused content-length calculation failures.
When n8n's HTTP Request node attempted to upload binary files via multipart form-data, the requests could fail silently or timeout in production — even though the same workflow worked fine in local development. This frustrating inconsistency had two root causes, both addressed in this fix.
First, the code used instanceof FormData to identify form data objects. In production npm installations, different packages can resolve separate copies of the form-data module, causing instanceof to return false even when the object is legitimately a FormData instance. When this check failed, the code would destroy the FormData by spreading it as a plain object and recreating it — losing all the stream data in the process. A new duck-type checking function now validates FormData instances by looking for the required getHeaders and append methods, with instanceof as a fast path for environments where it works.
Second, when appending binary streams to FormData, the file size wasn't being provided. The form-data package couldn't measure stream length on its own, causing content-length header calculation to fail silently. Servers that require this header would then reject or timeout the request. The fix retrieves file metadata to obtain the size and passes it as knownLength when appending streams.
These changes touch the core execution engine in packages/core and the HTTP Request node implementation in packages/nodes-base, ensuring consistent behavior across different installation methods.
View Original GitHub Description
Summary
Fixes multipart/form-data file uploads failing when binary data is stored in filesystem mode (the default for production n8n). Two root causes:
-
instanceof FormDatafails across packages — Whenpackages/coreandpackages/nodes-baseresolve separate copies of theform-datamodule (common with npm/npx installs),instanceofreturnsfalse. The code then destroys the FormData by spreading it as a plain object and re-creating it, losing all stream data. Fixed by addingisFormDataInstance()— a duck-type check with aninstanceoffast path. This is the root cause for the differing behavior betweennpx n8nand a local dev build: pnpm deduplicates to a single shared copy ofform-data, soinstanceofsucceeds locally. -
Missing
knownLengthfor binary streams —getBinaryStream()returns aReadablestream whose length theform-datapackage cannot measure, causingcontent-lengthcalculation to fail silently. Servers that requirecontent-lengththen reject or time out the request. Fixed by callinggetBinaryMetadata()to obtain the file size and passing it asknownLengthwhen appending streams to FormData.
How to test
- Create an empty folder and initialise it with
npm init -y - Install n8n:
npm install --save n8nand add a run script"n8n": "n8n"topackage.json - Start n8n:
npm run n8n(reproduces the same dependency layout asnpx n8n) - Create a workflow: Manual Trigger → Read Binary File → HTTP Request (POST, body type Form-Data, with an
n8n Binary Fileparameter) - Verify the upload completes without "Unable to calculate form data length" errors and that
content-lengthis set correctly — use RequestBin or a similar tool to inspect the incoming request headers and boundary values
Related Linear tickets, GitHub issues, and community forum posts
- https://linear.app/n8n/issue/NODE-4730
- https://linear.app/n8n/issue/N8N-9861
- Fixes https://github.com/n8n-io/n8n/issues/27533
- Supersedes https://github.com/n8n-io/n8n/pull/28047
Review / Merge checklist
- PR title and summary are descriptive. (conventions)
- Docs updated or follow-up ticket created.
- Tests included.
- PR Labeled with
release/backport(if the PR is an urgent fix that needs to be backported)