Skip to content

Commit 442049b

Browse files
committed
Fix: Suspend while recovering from hydration error (#28800)
Fixes a bug that happens when an error occurs during hydration, React switches to client rendering, and then the client render suspends. It works correctly if there's a Suspense boundary on the stack, but not if it happens in the shell of the app. Prior to this fix, the app would crash with an "Unknown root exit status" error. I left a TODO comment for how we might refactor this code to be less confusing in the future. DiffTrain build for [3f9e237](3f9e237)
1 parent a85aedc commit 442049b

17 files changed

+209
-81
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
64c8d2d45d49dbb2f59ea23e5e739eb79e124abc
1+
3f9e237a2feb74f1fca23b76d9d2e9e1713e2ba1

compiled/facebook-www/ReactART-dev.classic.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ if (__DEV__) {
6666
return self;
6767
}
6868

69-
var ReactVersion = "19.0.0-www-classic-8ce767ac";
69+
var ReactVersion = "19.0.0-www-classic-877fd74a";
7070

7171
var LegacyRoot = 0;
7272
var ConcurrentRoot = 1;
@@ -26099,20 +26099,31 @@ if (__DEV__) {
2609926099
} // Check if something threw
2610026100

2610126101
if (exitStatus === RootErrored) {
26102-
var originallyAttemptedLanes = lanes;
26102+
var lanesThatJustErrored = lanes;
2610326103
var errorRetryLanes = getLanesToRetrySynchronouslyOnError(
2610426104
root,
26105-
originallyAttemptedLanes
26105+
lanesThatJustErrored
2610626106
);
2610726107

2610826108
if (errorRetryLanes !== NoLanes) {
2610926109
lanes = errorRetryLanes;
2611026110
exitStatus = recoverFromConcurrentError(
2611126111
root,
26112-
originallyAttemptedLanes,
26112+
lanesThatJustErrored,
2611326113
errorRetryLanes
2611426114
);
26115-
renderWasConcurrent = false;
26115+
renderWasConcurrent = false; // Need to check the exit status again.
26116+
26117+
if (exitStatus !== RootErrored) {
26118+
// The root did not error this time. Restart the exit algorithm
26119+
// from the beginning.
26120+
// TODO: Refactor the exit algorithm to be less confusing. Maybe
26121+
// more branches + recursion instead of a loop. I think the only
26122+
// thing that causes it to be a loop is the RootDidNotComplete
26123+
// check. If that's true, then we don't need a loop/recursion
26124+
// at all.
26125+
continue;
26126+
}
2611626127
}
2611726128
}
2611826129

compiled/facebook-www/ReactART-dev.modern.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ if (__DEV__) {
6666
return self;
6767
}
6868

69-
var ReactVersion = "19.0.0-www-modern-070c93c4";
69+
var ReactVersion = "19.0.0-www-modern-bf3441a6";
7070

7171
var LegacyRoot = 0;
7272
var ConcurrentRoot = 1;
@@ -25306,20 +25306,31 @@ if (__DEV__) {
2530625306
} // Check if something threw
2530725307

2530825308
if (exitStatus === RootErrored) {
25309-
var originallyAttemptedLanes = lanes;
25309+
var lanesThatJustErrored = lanes;
2531025310
var errorRetryLanes = getLanesToRetrySynchronouslyOnError(
2531125311
root,
25312-
originallyAttemptedLanes
25312+
lanesThatJustErrored
2531325313
);
2531425314

2531525315
if (errorRetryLanes !== NoLanes) {
2531625316
lanes = errorRetryLanes;
2531725317
exitStatus = recoverFromConcurrentError(
2531825318
root,
25319-
originallyAttemptedLanes,
25319+
lanesThatJustErrored,
2532025320
errorRetryLanes
2532125321
);
25322-
renderWasConcurrent = false;
25322+
renderWasConcurrent = false; // Need to check the exit status again.
25323+
25324+
if (exitStatus !== RootErrored) {
25325+
// The root did not error this time. Restart the exit algorithm
25326+
// from the beginning.
25327+
// TODO: Refactor the exit algorithm to be less confusing. Maybe
25328+
// more branches + recursion instead of a loop. I think the only
25329+
// thing that causes it to be a loop is the RootDidNotComplete
25330+
// check. If that's true, then we don't need a loop/recursion
25331+
// at all.
25332+
continue;
25333+
}
2532325334
}
2532425335
}
2532525336

compiled/facebook-www/ReactART-prod.classic.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9091,13 +9091,18 @@ function performConcurrentWorkOnRoot(root, didTimeout) {
90919091
root,
90929092
renderWasConcurrent
90939093
);
9094-
0 !== errorRetryLanes &&
9094+
if (
9095+
0 !== errorRetryLanes &&
90959096
((lanes = errorRetryLanes),
90969097
(exitStatus = recoverFromConcurrentError(
90979098
root,
90989099
renderWasConcurrent,
90999100
errorRetryLanes
9100-
)));
9101+
)),
9102+
(renderWasConcurrent = !1),
9103+
2 !== exitStatus)
9104+
)
9105+
continue;
91019106
}
91029107
if (1 === exitStatus) {
91039108
prepareFreshStack(root, 0);
@@ -10594,7 +10599,7 @@ var slice = Array.prototype.slice,
1059410599
return null;
1059510600
},
1059610601
bundleType: 0,
10597-
version: "19.0.0-www-classic-e80018a0",
10602+
version: "19.0.0-www-classic-f1bbc587",
1059810603
rendererPackageName: "react-art"
1059910604
};
1060010605
var internals$jscomp$inline_1322 = {
@@ -10625,7 +10630,7 @@ var internals$jscomp$inline_1322 = {
1062510630
scheduleRoot: null,
1062610631
setRefreshHandler: null,
1062710632
getCurrentFiber: null,
10628-
reconcilerVersion: "19.0.0-www-classic-e80018a0"
10633+
reconcilerVersion: "19.0.0-www-classic-f1bbc587"
1062910634
};
1063010635
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
1063110636
var hook$jscomp$inline_1323 = __REACT_DEVTOOLS_GLOBAL_HOOK__;

compiled/facebook-www/ReactART-prod.modern.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8619,13 +8619,18 @@ function performConcurrentWorkOnRoot(root, didTimeout) {
86198619
root,
86208620
renderWasConcurrent
86218621
);
8622-
0 !== errorRetryLanes &&
8622+
if (
8623+
0 !== errorRetryLanes &&
86238624
((lanes = errorRetryLanes),
86248625
(exitStatus = recoverFromConcurrentError(
86258626
root,
86268627
renderWasConcurrent,
86278628
errorRetryLanes
8628-
)));
8629+
)),
8630+
(renderWasConcurrent = !1),
8631+
2 !== exitStatus)
8632+
)
8633+
continue;
86298634
}
86308635
if (1 === exitStatus) {
86318636
prepareFreshStack(root, 0);
@@ -10073,7 +10078,7 @@ var slice = Array.prototype.slice,
1007310078
return null;
1007410079
},
1007510080
bundleType: 0,
10076-
version: "19.0.0-www-modern-2ada2d66",
10081+
version: "19.0.0-www-modern-4749dbb1",
1007710082
rendererPackageName: "react-art"
1007810083
};
1007910084
var internals$jscomp$inline_1307 = {
@@ -10104,7 +10109,7 @@ var internals$jscomp$inline_1307 = {
1010410109
scheduleRoot: null,
1010510110
setRefreshHandler: null,
1010610111
getCurrentFiber: null,
10107-
reconcilerVersion: "19.0.0-www-modern-2ada2d66"
10112+
reconcilerVersion: "19.0.0-www-modern-4749dbb1"
1010810113
};
1010910114
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
1011010115
var hook$jscomp$inline_1308 = __REACT_DEVTOOLS_GLOBAL_HOOK__;

compiled/facebook-www/ReactDOM-dev.classic.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31812,20 +31812,31 @@ if (__DEV__) {
3181231812
} // Check if something threw
3181331813

3181431814
if (exitStatus === RootErrored) {
31815-
var originallyAttemptedLanes = lanes;
31815+
var lanesThatJustErrored = lanes;
3181631816
var errorRetryLanes = getLanesToRetrySynchronouslyOnError(
3181731817
root,
31818-
originallyAttemptedLanes
31818+
lanesThatJustErrored
3181931819
);
3182031820

3182131821
if (errorRetryLanes !== NoLanes) {
3182231822
lanes = errorRetryLanes;
3182331823
exitStatus = recoverFromConcurrentError(
3182431824
root,
31825-
originallyAttemptedLanes,
31825+
lanesThatJustErrored,
3182631826
errorRetryLanes
3182731827
);
31828-
renderWasConcurrent = false;
31828+
renderWasConcurrent = false; // Need to check the exit status again.
31829+
31830+
if (exitStatus !== RootErrored) {
31831+
// The root did not error this time. Restart the exit algorithm
31832+
// from the beginning.
31833+
// TODO: Refactor the exit algorithm to be less confusing. Maybe
31834+
// more branches + recursion instead of a loop. I think the only
31835+
// thing that causes it to be a loop is the RootDidNotComplete
31836+
// check. If that's true, then we don't need a loop/recursion
31837+
// at all.
31838+
continue;
31839+
}
3182931840
}
3183031841
}
3183131842

@@ -36145,7 +36156,7 @@ if (__DEV__) {
3614536156
return root;
3614636157
}
3614736158

36148-
var ReactVersion = "19.0.0-www-classic-4106d899";
36159+
var ReactVersion = "19.0.0-www-classic-87a9d756";
3614936160

3615036161
function createPortal$1(
3615136162
children,

compiled/facebook-www/ReactDOM-dev.modern.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39589,20 +39589,31 @@ if (__DEV__) {
3958939589
} // Check if something threw
3959039590

3959139591
if (exitStatus === RootErrored) {
39592-
var originallyAttemptedLanes = lanes;
39592+
var lanesThatJustErrored = lanes;
3959339593
var errorRetryLanes = getLanesToRetrySynchronouslyOnError(
3959439594
root,
39595-
originallyAttemptedLanes
39595+
lanesThatJustErrored
3959639596
);
3959739597

3959839598
if (errorRetryLanes !== NoLanes) {
3959939599
lanes = errorRetryLanes;
3960039600
exitStatus = recoverFromConcurrentError(
3960139601
root,
39602-
originallyAttemptedLanes,
39602+
lanesThatJustErrored,
3960339603
errorRetryLanes
3960439604
);
39605-
renderWasConcurrent = false;
39605+
renderWasConcurrent = false; // Need to check the exit status again.
39606+
39607+
if (exitStatus !== RootErrored) {
39608+
// The root did not error this time. Restart the exit algorithm
39609+
// from the beginning.
39610+
// TODO: Refactor the exit algorithm to be less confusing. Maybe
39611+
// more branches + recursion instead of a loop. I think the only
39612+
// thing that causes it to be a loop is the RootDidNotComplete
39613+
// check. If that's true, then we don't need a loop/recursion
39614+
// at all.
39615+
continue;
39616+
}
3960639617
}
3960739618
}
3960839619

@@ -45641,7 +45652,7 @@ if (__DEV__) {
4564145652
return root;
4564245653
}
4564345654

45644-
var ReactVersion = "19.0.0-www-modern-d80f9f9e";
45655+
var ReactVersion = "19.0.0-www-modern-1c3b0b72";
4564545656

4564645657
function createPortal$1(
4564745658
children,

compiled/facebook-www/ReactDOM-prod.classic.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10891,13 +10891,18 @@ function performConcurrentWorkOnRoot(root, didTimeout) {
1089110891
root,
1089210892
renderWasConcurrent
1089310893
);
10894-
0 !== errorRetryLanes &&
10894+
if (
10895+
0 !== errorRetryLanes &&
1089510896
((lanes = errorRetryLanes),
1089610897
(exitStatus = recoverFromConcurrentError(
1089710898
root,
1089810899
renderWasConcurrent,
1089910900
errorRetryLanes
10900-
)));
10901+
)),
10902+
(renderWasConcurrent = !1),
10903+
2 !== exitStatus)
10904+
)
10905+
continue;
1090110906
}
1090210907
if (1 === exitStatus) {
1090310908
prepareFreshStack(root, 0);
@@ -16991,7 +16996,7 @@ Internals.Events = [
1699116996
var devToolsConfig$jscomp$inline_1727 = {
1699216997
findFiberByHostInstance: getClosestInstanceFromNode,
1699316998
bundleType: 0,
16994-
version: "19.0.0-www-classic-007b0a8e",
16999+
version: "19.0.0-www-classic-1ce9ab8c",
1699517000
rendererPackageName: "react-dom"
1699617001
};
1699717002
var internals$jscomp$inline_2155 = {
@@ -17021,7 +17026,7 @@ var internals$jscomp$inline_2155 = {
1702117026
scheduleRoot: null,
1702217027
setRefreshHandler: null,
1702317028
getCurrentFiber: null,
17024-
reconcilerVersion: "19.0.0-www-classic-007b0a8e"
17029+
reconcilerVersion: "19.0.0-www-classic-1ce9ab8c"
1702517030
};
1702617031
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
1702717032
var hook$jscomp$inline_2156 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -17484,4 +17489,4 @@ exports.useFormState = function (action, initialState, permalink) {
1748417489
exports.useFormStatus = function () {
1748517490
return ReactSharedInternals.H.useHostTransitionStatus();
1748617491
};
17487-
exports.version = "19.0.0-www-classic-007b0a8e";
17492+
exports.version = "19.0.0-www-classic-1ce9ab8c";

compiled/facebook-www/ReactDOM-prod.modern.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13491,13 +13491,18 @@ function performConcurrentWorkOnRoot(root, didTimeout) {
1349113491
root,
1349213492
renderWasConcurrent
1349313493
);
13494-
0 !== errorRetryLanes &&
13494+
if (
13495+
0 !== errorRetryLanes &&
1349513496
((lanes = errorRetryLanes),
1349613497
(exitStatus = recoverFromConcurrentError(
1349713498
root,
1349813499
renderWasConcurrent,
1349913500
errorRetryLanes
13500-
)));
13501+
)),
13502+
(renderWasConcurrent = !1),
13503+
2 !== exitStatus)
13504+
)
13505+
continue;
1350113506
}
1350213507
if (1 === exitStatus) {
1350313508
prepareFreshStack(root, 0);
@@ -16353,7 +16358,7 @@ Internals.Events = [
1635316358
var devToolsConfig$jscomp$inline_1720 = {
1635416359
findFiberByHostInstance: getClosestInstanceFromNode,
1635516360
bundleType: 0,
16356-
version: "19.0.0-www-modern-00807ede",
16361+
version: "19.0.0-www-modern-b5e235f2",
1635716362
rendererPackageName: "react-dom"
1635816363
};
1635916364
var internals$jscomp$inline_2157 = {
@@ -16383,7 +16388,7 @@ var internals$jscomp$inline_2157 = {
1638316388
scheduleRoot: null,
1638416389
setRefreshHandler: null,
1638516390
getCurrentFiber: null,
16386-
reconcilerVersion: "19.0.0-www-modern-00807ede"
16391+
reconcilerVersion: "19.0.0-www-modern-b5e235f2"
1638716392
};
1638816393
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
1638916394
var hook$jscomp$inline_2158 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -16688,4 +16693,4 @@ exports.useFormState = function (action, initialState, permalink) {
1668816693
exports.useFormStatus = function () {
1668916694
return ReactSharedInternals.H.useHostTransitionStatus();
1669016695
};
16691-
exports.version = "19.0.0-www-modern-00807ede";
16696+
exports.version = "19.0.0-www-modern-b5e235f2";

compiled/facebook-www/ReactDOM-profiling.classic.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11484,13 +11484,18 @@ function performConcurrentWorkOnRoot(root, didTimeout) {
1148411484
root,
1148511485
renderWasConcurrent
1148611486
);
11487-
0 !== errorRetryLanes &&
11487+
if (
11488+
0 !== errorRetryLanes &&
1148811489
((lanes = errorRetryLanes),
1148911490
(exitStatus = recoverFromConcurrentError(
1149011491
root,
1149111492
renderWasConcurrent,
1149211493
errorRetryLanes
11493-
)));
11494+
)),
11495+
(renderWasConcurrent = !1),
11496+
2 !== exitStatus)
11497+
)
11498+
continue;
1149411499
}
1149511500
if (1 === exitStatus) {
1149611501
prepareFreshStack(root, 0);
@@ -17739,7 +17744,7 @@ Internals.Events = [
1773917744
var devToolsConfig$jscomp$inline_1813 = {
1774017745
findFiberByHostInstance: getClosestInstanceFromNode,
1774117746
bundleType: 0,
17742-
version: "19.0.0-www-classic-5bbd766e",
17747+
version: "19.0.0-www-classic-6860f048",
1774317748
rendererPackageName: "react-dom"
1774417749
};
1774517750
(function (internals) {
@@ -17783,7 +17788,7 @@ var devToolsConfig$jscomp$inline_1813 = {
1778317788
scheduleRoot: null,
1778417789
setRefreshHandler: null,
1778517790
getCurrentFiber: null,
17786-
reconcilerVersion: "19.0.0-www-classic-5bbd766e"
17791+
reconcilerVersion: "19.0.0-www-classic-6860f048"
1778717792
});
1778817793
var ReactFiberErrorDialogWWW = require("ReactFiberErrorDialog");
1778917794
if ("function" !== typeof ReactFiberErrorDialogWWW.showErrorDialog)
@@ -18233,7 +18238,7 @@ exports.useFormState = function (action, initialState, permalink) {
1823318238
exports.useFormStatus = function () {
1823418239
return ReactSharedInternals.H.useHostTransitionStatus();
1823518240
};
18236-
exports.version = "19.0.0-www-classic-5bbd766e";
18241+
exports.version = "19.0.0-www-classic-6860f048";
1823718242
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1823818243
"function" ===
1823918244
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)