Skip to content

[FlightReply] Don't drop FormData entries in decodeReplyFromBusboy#36468

Open
unstubbable wants to merge 3 commits into
facebook:mainfrom
unstubbable:fix-form-data-regression
Open

[FlightReply] Don't drop FormData entries in decodeReplyFromBusboy#36468
unstubbable wants to merge 3 commits into
facebook:mainfrom
unstubbable:fix-form-data-regression

Conversation

@unstubbable
Copy link
Copy Markdown
Collaborator

Fixes a regression from #36425 where referenced FormData entries can be dropped by decodeReplyFromBusboy when files are interleaved with text fields in the payload.

decodeReplyFromBusboy queues text fields that arrive while a file is being streamed and flushes them after the last file's 'end', working around busboy emitting 'end' deferred relative to subsequent 'field' events. With multiple files interleaved with text, this loses the relative order of the affected text entries. The reorder was a long-standing but invisible issue — entries came back in the wrong order but were all present — until #36425 tightened how referenced FormData entries are collected from the backing store to rely on them being contiguous. With that assumption violated, referenced FormDatas can now come back with some entries dropped. The pattern is most easily surfaced through useActionState actions that return the submitted FormData as part of their state.

This replaces the tail-flush with a positionally-tagged buffer drained in arrival order. flush() walks from a monotonic index pointer, resolving text immediately and files once their 'end' has fired, and holding later entries when the cursor lands on a still-streaming file. The backing FormData now matches the payload's order, restoring the contiguity assumption (and fixing the long-standing reorder as a side effect). The same change is applied to all five copies in react-server-dom-{webpack,turbopack,parcel,esm,unbundled}. Two new tests cover the multi-file interleave.

fixes vercel/next.js#93822

@meta-cla meta-cla Bot added the CLA Signed label May 13, 2026
@github-actions github-actions Bot added the React Core Team Opened by a member of the React Core Team label May 13, 2026
@unstubbable unstubbable force-pushed the fix-form-data-regression branch from 350689b to d94bedc Compare May 13, 2026 22:22
@react-sizebot
Copy link
Copy Markdown

react-sizebot commented May 13, 2026

Comparing: 8fc5763...5978b45

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.84 kB 6.84 kB +0.11% 1.88 kB 1.88 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 614.17 kB 614.17 kB = 108.52 kB 108.52 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.84 kB 6.84 kB +0.05% 1.88 kB 1.89 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 680.11 kB 680.11 kB = 119.48 kB 119.48 kB
facebook-www/ReactDOM-prod.classic.js = 700.53 kB 700.53 kB = 123.06 kB 123.05 kB
facebook-www/ReactDOM-prod.modern.js = 690.84 kB 690.84 kB = 121.44 kB 121.44 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +0.93% 115.46 kB 116.54 kB +0.88% 23.35 kB 23.55 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +0.93% 115.46 kB 116.54 kB +0.88% 23.35 kB 23.55 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.production.js +0.92% 117.26 kB 118.33 kB +0.87% 23.71 kB 23.92 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.production.js +0.90% 119.53 kB 120.60 kB +0.85% 23.93 kB 24.14 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.production.js +0.90% 119.53 kB 120.60 kB +0.85% 23.93 kB 24.14 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.production.js +0.89% 121.32 kB 122.40 kB +0.83% 24.30 kB 24.50 kB
oss-stable-semver/react-server-dom-unbundled/cjs/react-server-dom-unbundled-server.node.production.js +0.86% 125.40 kB 126.47 kB +0.84% 24.86 kB 25.07 kB
oss-stable/react-server-dom-unbundled/cjs/react-server-dom-unbundled-server.node.production.js +0.86% 125.40 kB 126.47 kB +0.84% 24.86 kB 25.07 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js +0.85% 126.44 kB 127.52 kB +0.84% 25.10 kB 25.31 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js +0.85% 126.44 kB 127.52 kB +0.84% 25.10 kB 25.31 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.production.js +0.85% 126.46 kB 127.53 kB +0.84% 25.09 kB 25.30 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.production.js +0.85% 126.46 kB 127.53 kB +0.84% 25.09 kB 25.30 kB
oss-experimental/react-server-dom-unbundled/cjs/react-server-dom-unbundled-server.node.production.js +0.85% 127.19 kB 128.26 kB +0.84% 25.24 kB 25.45 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.production.js +0.84% 128.24 kB 129.31 kB +0.82% 25.47 kB 25.68 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.production.js +0.84% 128.25 kB 129.32 kB +0.83% 25.46 kB 25.67 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +0.55% 236.07 kB 237.37 kB +0.55% 42.90 kB 43.14 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +0.55% 236.07 kB 237.37 kB +0.55% 42.90 kB 43.14 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js +0.55% 238.16 kB 239.46 kB +0.57% 43.33 kB 43.58 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +0.53% 242.84 kB 244.14 kB +0.66% 43.51 kB 43.80 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +0.53% 242.84 kB 244.14 kB +0.66% 43.51 kB 43.80 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-server.node.development.js +0.53% 244.93 kB 246.23 kB +0.63% 43.95 kB 44.23 kB
oss-stable-semver/react-server-dom-unbundled/cjs/react-server-dom-unbundled-server.node.development.js +0.52% 249.36 kB 250.66 kB +0.61% 44.60 kB 44.87 kB
oss-stable/react-server-dom-unbundled/cjs/react-server-dom-unbundled-server.node.development.js +0.52% 249.36 kB 250.66 kB +0.61% 44.60 kB 44.87 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +0.52% 250.56 kB 251.86 kB +0.60% 44.92 kB 45.19 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +0.52% 250.56 kB 251.86 kB +0.60% 44.92 kB 45.19 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +0.52% 250.57 kB 251.87 kB +0.61% 44.92 kB 45.19 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +0.52% 250.57 kB 251.87 kB +0.61% 44.92 kB 45.19 kB
oss-experimental/react-server-dom-unbundled/cjs/react-server-dom-unbundled-server.node.development.js +0.52% 251.45 kB 252.75 kB +0.60% 45.03 kB 45.31 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js +0.51% 252.65 kB 253.95 kB +0.60% 45.34 kB 45.61 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.node.development.js +0.51% 252.66 kB 253.96 kB +0.60% 45.35 kB 45.62 kB

Generated by 🚫 dangerJS against 5978b45

Copy link
Copy Markdown
Collaborator

@gnoff gnoff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could store queueFields on the file entry. always push to the top pendingFile.

Then you only flush when you get data an end even on value and you flush each file followed by it's queueFields until you hit the next pending file. splice the files array to eliminate flushed files and fields

@unstubbable unstubbable force-pushed the fix-form-data-regression branch from d94bedc to 393e3aa Compare May 13, 2026 23:26
Fixes a regression from facebook#36425 where referenced `FormData` entries can
be dropped by `decodeReplyFromBusboy` when files are interleaved with
text fields in the payload.

`decodeReplyFromBusboy` queues text fields that arrive while a file is
being streamed and flushes them after the last file's `'end'`, working
around busboy emitting `'end'` deferred relative to subsequent `'field'`
events. With multiple files interleaved with text, this loses the
relative order of the affected text entries. The reorder was a
long-standing but invisible issue — entries came back in the wrong order
but were all present — until facebook#36425 tightened how referenced FormData
entries are collected from the backing store to rely on them being
contiguous. With that assumption violated, referenced FormDatas can now
come back with some entries dropped. The pattern is most easily surfaced
through `useActionState` actions that return the submitted `FormData` as
part of their state.

This replaces the tail-flush with a positionally-tagged buffer drained
in arrival order. `flush()` walks from a monotonic index pointer,
resolving text immediately and files once their `'end'` has fired, and
holding later entries when the cursor lands on a still-streaming file.
The backing FormData now matches the payload's order, restoring the
contiguity assumption (and fixing the long-standing reorder as a side
effect). The same change is applied to all five copies in
`react-server-dom-{webpack,turbopack,parcel,esm,unbundled}`. Two new
tests cover the multi-file interleave.

fixes vercel/next.js#93822
@unstubbable unstubbable force-pushed the fix-form-data-regression branch from 76b9503 to 5978b45 Compare May 13, 2026 23:40
@unstubbable unstubbable marked this pull request as ready for review May 14, 2026 00:13
@unstubbable unstubbable requested a review from gnoff May 14, 2026 00:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed React Core Team Opened by a member of the React Core Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

useActionState with form containing file input receives missmatched FormData

3 participants