@samitouri / QOS-React-1 / commits / e2659d9d50

[Flight] Tailor the warning for binary data with a toJSON (Node Buffer) (#36873)

A Node.js `Buffer` carries a `toJSON` method, so Flight serializes it through that method instead of as binary, and it is deserialized as a plain `{type: 'Buffer', data: [...]}` object rather than a `Buffer` or `Uint8Array`. The warning React emits in this case reads "Uint8Array objects are not supported", which is misleading on two counts: the value is actually a `Buffer`, reported as `Uint8Array` only because that is its `Object.prototype.toString` tag, and a real `Uint8Array` is in fact supported, since it has no `toJSON` and serializes as binary. This makes the message especially confusing when binary data such as a font is passed as a serialized value. The first commit adds a test that pins down the current behavior, capturing both the misleading warning and the deserialization to a plain `{type: 'Buffer', data: [...]}` object. The second commit replaces the warning, for values that are `ArrayBuffer.isView`, with one that names the actual cause and the fix: the data is serialized through `toJSON` instead of as binary, so a `Uint8Array` or `ArrayBuffer` should be passed to send binary data. The new branch only fires for a typed array that also carries a `toJSON`, which in practice is a Node `Buffer`; a plain `Uint8Array` or `ArrayBuffer` has no `toJSON`, never reaches this branch, and continues to serialize as binary.

Hendrik Liebau committed Jun 24, 2026 at 21:04 UTC e2659d9d50d5bfca44b72daf961ff28e3696ea1a
2 files changed +39 -1
packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js
+27
@@ -2394,4 +2394,31 @@ describe('ReactFlightDOMNode', () => {
2394 // the next 1024-byte window.
2395 expect(result.payload).toEqual(binaryData);
2396 });
2397 +
2398 + // A Node.js Buffer carries a `toJSON` method, so Flight serializes it through
2399 + // that method instead of as binary, and warns. It is therefore deserialized
2400 + // as a plain `{type: 'Buffer', data: [...]}` object rather than a
2401 + // Buffer/Uint8Array.
2402 + it('serializes a Node Buffer through its toJSON and warns', async () => {
2403 + const buffer = Buffer.from([1, 2, 3, 4]);
2404 + const stream = await serverAct(() =>
2405 + ReactServerDOMServer.renderToPipeableStream({font: buffer}),
2406 + );
2407 + assertConsoleErrorDev([
2408 + 'Binary data with a toJSON method, such as a Node.js Buffer, is ' +
2409 + 'serialized through toJSON instead of as binary. Pass a ' +
2410 + 'Uint8Array or ArrayBuffer to send binary data.\n' +
2411 + ' {font: Uint8Array}\n' +
2412 + ' ^^^^^^^^^^',
2413 + ]);
2414 + const readable = new Stream.PassThrough(streamOptions);
2415 + const promise = ReactServerDOMClient.createFromNodeStream(readable, {
2416 + moduleMap: {},
2417 + moduleLoading: webpackModuleLoading,
2418 + });
2419 + stream.pipe(readable);
2420 + const result = await promise;
2421 + expect(Buffer.isBuffer(result.font)).toBe(false);
2422 + expect(result.font).toEqual({type: 'Buffer', data: [1, 2, 3, 4]});
2423 + });
2424 });
packages/react-server/src/ReactFlightServer.js
+12 -1
@@ -2822,7 +2822,18 @@ function resolveModel(
2822 // Call with the server component as the currently rendering component
2823 // for context.
2824 callWithDebugContextInDEV(request, task, () => {
2825 - if (objectName(originalValue) !== 'Object') {
2825 + if (ArrayBuffer.isView(originalValue)) {
2826 + // Binary data such as a Node.js Buffer carries a toJSON method, so it
2827 + // is serialized through that method rather than as binary. A plain
2828 + // Uint8Array or ArrayBuffer has no toJSON and is serialized as
2829 + // binary.
2830 + console.error(
2831 + 'Binary data with a toJSON method, such as a Node.js Buffer, is ' +
2832 + 'serialized through toJSON instead of as binary. Pass a ' +
2833 + 'Uint8Array or ArrayBuffer to send binary data.%s',
2834 + describeObjectForErrorMessage(parent, parentPropertyName),
2835 + );
2836 + } else if (objectName(originalValue) !== 'Object') {
2837 const jsxParentType = jsxChildrenParents.get(parent);
2838 if (typeof jsxParentType === 'string') {
2839 console.error(