[Flight] Cyclic references inside Map/Set values are silently corrupted to null on the client
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 55/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- javascript, react
- Área
- full-stack
Línea de trabajo
Empieza en packages/react-server/src/ReactFlightServer.js leyendo serializeMap y serializeSet, y luego ejecuta la reproducción proporcionada de renderToPipeableStream/createFromNodeStream. Sigue el recorrido del cliente para el manejo de ciclos de las referencias hasta la fila de serialización de Map/Set. Se considera terminado cuando los tres autociclos reportados se resuelven en sus instancias reales de Map/Set en lugar de null.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Description
Cyclic references inside Map/Set values are silently corrupted to null when serialized with React Server Components (Flight) and parsed on the client. Cyclic references in plain objects/arrays work fine (and are officially tested), so the Map/Set case is a data-corruption bug, not a "unsupported input" case.
Affected versions: tested on react-server-dom-webpack@19.3.0 (latest stable).
Reproduction
// server
import {renderToPipeableStream} from 'react-server-dom-webpack/server.node';
// client
import {createFromNodeStream} from 'react-server-dom-webpack/client';
// Case 1: Map value self-cycle
const m = new Map();
m.set('self', m);
// Case 2: Set self-cycle
const s = new Set();
s.add(s);
// Case 3: Set contains an object that references the Set back
const s2 = new Set();
const o = {back: s2};
s2.add(o);
const model = {m, s, s2};
// renderToPipeableStream(model, webpackMap) -> stream
// createFromNodeStream(stream, webpackMap)
Result (client side):
result.m.get('self') === null; // expected: === m (the Map itself)
[...result.s][0] === null; // expected: === s (the Set itself)
[...result.s2][0].back === null; // expected: === s2 (the Set itself)
Note: m.get('self') returns null, not m. No error is thrown — the cycle is silently lost.
Working control cases (for comparison)
The same shapes with plain objects and arrays round-trip correctly (React officially supports cyclic objects/arrays):
const cycObj = {name: 'x'};
cycObj.self = cycObj; // ok, back: cycObj.self === cycObj
const cycArr = [1];
cycArr.push(cycArr); // ok
// A Map whose value points to an independent (non-cyclic) object path also works:
const foo = {};
const set = new Set([foo]);
foo.bar = set; // ok: set contains foo, foo.bar === set
The failing cases all have one thing in common: the cycle references back to the Map/Set's own serialization position (either the Map/Set is the root, or the reference goes through the property that holds the Map/Set, e.g. $0, $0:s, $0:m in the wire format).
Root cause
serializeMap/serializeSet (packages/react-server/src/ReactFlightServer.js) outline the entries into a separate chunk/row:
function serializeMap(request, map) {
const entries = Array.from(map);
const id = outlineModel(request, entries);
return '$Q' + id.toString(16);
}
Wire format for {m: m} where m.set('self', m):
0:{"m":"$Q1"}
1:[["self","$0:m"]]
The client parses row 1 (the Map entries) while row 0 (the root) is still blocked waiting for row 1; row 1 references $0:m which requires row 0 to be initialized. This cycle is not broken by the client's cycle-handling logic, so the reference resolves to null. Plain objects/arrays are inlined into the parent row and go through the reviver/reify path, where cyclic references are handled correctly.
Related: #37542 fixed cyclic references for the case where the reference points to an independently-resolvable object (e.g. Set([foo]) + foo.bar = set + Promise-wrapped rows). The Map/Set cases above (references that close back onto the Map/Set's own row) are still broken after that fix.
Expected behavior
Cyclic references inside Map/Set should resolve to the actual Map/Set instance, consistent with cyclic plain objects/arrays. At minimum, a corrupted cycle should not silently become null.
- Lenguaje dominante
- JavaScript
- Estrellas
- 251k
- Forks
- 51.4k
- Merge medio
- 2 d 1 h
- PR fusionados (30 d)
- 51
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de react/react
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
Todos los issues de react/react
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
avniproject/avni-client#2135 ·
-
enhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
babalae/bettergi-scripts-list#3674 ·
-
A-Release-Notes C-Editing D-Modest S-Ready-For-Implementation
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
bevyengine/bevy-website#2595 ·
-
ecosystem wording
Dificultad 1/5 Menos de una hora Aptitud para principiantes 90/100
matrix-org/matrix.org#3649 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
vadimdemedes/ink#1029 ·