My team and I maintain a legacy PHP web application for large file transfers. The application stack is LAMP-like, leveraging NGINX and PHP-FPM. Recently, we have observed Firefox failing to upload a certain combination of files. When the page was using XHR, the progress bar tied to it would jump immediately 99% and then eventually fail to upload. Looking more closely at progress event, we observed that the loaded value appeared to be too large right from the start.
Reworking the page to use Fetch did not fix the problem, but it did make it easier to determine that the transfer was failing due to a network type error, not due to a failure response from the backend.
Neither Edge nor Chrome exhibit these same failures. Even more strangely, if the individual files are uploaded, Firefox succeeds in uploading them. If they are all zipped together, Firefox also succeeds in uploading them. It is only when they are appended individually to the form data that for the POST that Firefox fails.
We have attempted to rule out virus scanner or firewall interference by attempting the upload from non-work computers. We have also downgraded Firefox a few times to see if a recent upgrade was culprit. We have cleared out cookies and cache, reset profiles, ran the browser in Safe Mode, too.
NGINX access and error logs are showing nothing. No PHP errors. We are fairly stumped here and have been pretty exhaustive in our testing, research, and troubleshooting efforts.
We have also examined other Stack Overflow questions and answers that seemed relevant.
Why does Firefox consistently fail to upload a particular combination of files with a network error when other browsers succeed and Firefox itself succeeds if those files are instead uploaded individually or in a large zip file?
Microsoft Copilot was able to come up with some information that explains why the issue occurs and provide some potential workarounds:
Why Firefox Fails on Multi-File FormData Uploads
If you append more than one File
object to a single FormData
and POST it in Firefox, you’ll immediately see the upload “finish” (progress jumps to 100%) and then a NetworkError. Chrome and Edge never hit this failure, and even Firefox will upload those same files just fine if you:
Send them in separate requests
Zip them into one blob and send that single blob
What’s Happening Under the Hood
Firefox pre-buffers the entire multipart body
Firefox’s XHR/Fetch implementation must know the final Content-Length
before it hits the wire. To do that it internally builds (buffers) your entire multipart body in an nsPipe
. With multiple File
entries—even if each one streams off disk by itself—the combination goes down a code path that fully buffers those streams and calculates length up front.
A corner-case in that buffering code trips a network failure
For some sets of files (size, type, metadata, boundary math) Firefox’s multipart builder errors out mid-buffer. The underlying I/O call returns a failure (e.g. NS_ERROR_FAILURE
), so the POST is immediately aborted at the network stack level.
Progress events lie by spec
The spec mandates that right before the error
event fires, the final progress
is dispatched with loaded == total
. That’s why you see the bar jump to 100%—even though nothing ever reached the server—followed immediately by the network error.
Chrome/Edge avoid this by streaming chunked bodies
Those browsers never need to pre-buffer the entire form payload. They stream each part as it becomes available, so they never hit the buggy code path that fails under Firefox’s multipart builder.
Proof and Bug References
Original Stack Overflow report: combination of files fails only in Firefox
WHATWG/XHR issue “Wrong upload progress when network interrupts” shows that on error Firefox drives loaded → total
then throws an error, while Chrome/Edge do not exhibit this failure
MDN’s spec on XMLHttpRequestUpload.progress
confirms the final‐event behavior
Workarounds
Upload files one at a time
for (let file of files) { const fd = new FormData(); fd.append('file', file); await fetch('/upload', { method: 'POST', body: fd }); }
Zip on the client into one Blob
Combine all files into a single zip‐Blob
(e.g. with JSZip), then append that one blob to your FormData
. Firefox’s code path for a single blob upload doesn’t hit the broken multipart builder.
Use a streaming multipart generator
Bypass FormData
entirely and construct the body as a ReadableStream
, writing boundaries and file chunks yourself. Firefox will stream it without pre-buffering.
Detect Firefox and fall back
If you detect navigator.userAgent
contains “Firefox,” switch to one of the above strategies.
When Will It Be Fixed?
This is a known Firefox bug in the multipart handling layer. Follow or star the upstream Bugzilla issue:
Until it lands in a stable Firefox release, apply one of the workarounds above whenever you need to upload multiple files in one go under Firefox.