Skip to content

Commit a0dc9da

Browse files
committed
Add a prefix to errors serialized from server rendering
It can be a bit confusing to see where this error came from otherwise since it didn't come from elsewhere on the client.
1 parent 73a50cb commit a0dc9da

File tree

4 files changed

+77
-59
lines changed

4 files changed

+77
-59
lines changed

packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,8 @@ describe('ReactDOMFizzServer', () => {
786786
errors,
787787
[
788788
[
789-
theError.message,
789+
'Switched to client rendering because the server rendering errored:\n\n' +
790+
theError.message,
790791
expectedDigest,
791792
componentStack(['Lazy', 'Suspense', 'div', 'App']),
792793
],
@@ -909,7 +910,8 @@ describe('ReactDOMFizzServer', () => {
909910
errors,
910911
[
911912
[
912-
theError.message,
913+
'Switched to client rendering because the server rendering errored:\n\n' +
914+
theError.message,
913915
expectedDigest,
914916
componentStack(['Lazy', 'Suspense', 'div', 'App']),
915917
],
@@ -992,7 +994,8 @@ describe('ReactDOMFizzServer', () => {
992994
errors,
993995
[
994996
[
995-
theError.message,
997+
'Switched to client rendering because the server rendering errored:\n\n' +
998+
theError.message,
996999
expectedDigest,
9971000
componentStack([
9981001
'Erroring',
@@ -1078,7 +1081,8 @@ describe('ReactDOMFizzServer', () => {
10781081
errors,
10791082
[
10801083
[
1081-
theError.message,
1084+
'Switched to client rendering because the server rendering errored:\n\n' +
1085+
theError.message,
10821086
expectedDigest,
10831087
componentStack(['Lazy', 'Suspense', 'div', 'App']),
10841088
],
@@ -1404,13 +1408,15 @@ describe('ReactDOMFizzServer', () => {
14041408
errors,
14051409
[
14061410
[
1407-
'The server did not finish this Suspense boundary: The render was aborted by the server without a reason.',
1411+
'Switched to client rendering because the server rendering aborted due to:\n\n' +
1412+
'The render was aborted by the server without a reason.',
14081413
expectedDigest,
14091414
// We get the stack of the task when it was aborted which is why we see `h1`
14101415
componentStack(['h1', 'Suspense', 'div', 'App']),
14111416
],
14121417
[
1413-
'The server did not finish this Suspense boundary: The render was aborted by the server without a reason.',
1418+
'Switched to client rendering because the server rendering aborted due to:\n\n' +
1419+
'The render was aborted by the server without a reason.',
14141420
expectedDigest,
14151421
componentStack(['Suspense', 'main', 'div', 'App']),
14161422
],
@@ -2145,7 +2151,8 @@ describe('ReactDOMFizzServer', () => {
21452151
errors,
21462152
[
21472153
[
2148-
theError.message,
2154+
'Switched to client rendering because the server rendering errored:\n\n' +
2155+
theError.message,
21492156
expectedDigest,
21502157
componentStack([
21512158
'AsyncText',
@@ -3431,12 +3438,14 @@ describe('ReactDOMFizzServer', () => {
34313438
errors,
34323439
[
34333440
[
3434-
'The server did not finish this Suspense boundary: foobar',
3441+
'Switched to client rendering because the server rendering aborted due to:\n\n' +
3442+
'foobar',
34353443
'a digest',
34363444
componentStack(['Suspense', 'p', 'div', 'App']),
34373445
],
34383446
[
3439-
'The server did not finish this Suspense boundary: foobar',
3447+
'Switched to client rendering because the server rendering aborted due to:\n\n' +
3448+
'foobar',
34403449
'a digest',
34413450
componentStack(['Suspense', 'span', 'div', 'App']),
34423451
],
@@ -3512,12 +3521,14 @@ describe('ReactDOMFizzServer', () => {
35123521
errors,
35133522
[
35143523
[
3515-
'The server did not finish this Suspense boundary: uh oh',
3524+
'Switched to client rendering because the server rendering aborted due to:\n\n' +
3525+
'uh oh',
35163526
'a digest',
35173527
componentStack(['Suspense', 'p', 'div', 'App']),
35183528
],
35193529
[
3520-
'The server did not finish this Suspense boundary: uh oh',
3530+
'Switched to client rendering because the server rendering aborted due to:\n\n' +
3531+
'uh oh',
35213532
'a digest',
35223533
componentStack(['Suspense', 'span', 'div', 'App']),
35233534
],
@@ -3991,7 +4002,8 @@ describe('ReactDOMFizzServer', () => {
39914002
errors,
39924003
[
39934004
[
3994-
theError.message,
4005+
'Switched to client rendering because the server rendering errored:\n\n' +
4006+
theError.message,
39954007
expectedDigest,
39964008
componentStack(['Erroring', 'Suspense', 'div', 'App']),
39974009
],
@@ -6772,7 +6784,14 @@ describe('ReactDOMFizzServer', () => {
67726784

67736785
expect(recoverableErrors).toEqual(
67746786
__DEV__
6775-
? ['server error', 'replay error', 'server error']
6787+
? [
6788+
'Switched to client rendering because the server rendering errored:\n\n' +
6789+
'server error',
6790+
'Switched to client rendering because the server rendering errored:\n\n' +
6791+
'replay error',
6792+
'Switched to client rendering because the server rendering errored:\n\n' +
6793+
'server error',
6794+
]
67766795
: [
67776796
'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
67786797
'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
@@ -6931,8 +6950,10 @@ describe('ReactDOMFizzServer', () => {
69316950
expect(recoverableErrors).toEqual(
69326951
__DEV__
69336952
? [
6934-
'The server did not finish this Suspense boundary: aborted',
6935-
'The server did not finish this Suspense boundary: aborted',
6953+
'Switched to client rendering because the server rendering aborted due to:\n\n' +
6954+
'aborted',
6955+
'Switched to client rendering because the server rendering aborted due to:\n\n' +
6956+
'aborted',
69366957
]
69376958
: [
69386959
'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
@@ -7103,8 +7124,10 @@ describe('ReactDOMFizzServer', () => {
71037124
// It surfaced in two different suspense boundaries.
71047125
__DEV__
71057126
? [
7106-
'The server did not finish this Suspense boundary: replay error',
7107-
'The server did not finish this Suspense boundary: replay error',
7127+
'Switched to client rendering because the server rendering aborted due to:\n\n' +
7128+
'replay error',
7129+
'Switched to client rendering because the server rendering aborted due to:\n\n' +
7130+
'replay error',
71087131
]
71097132
: [
71107133
'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
@@ -7230,7 +7253,10 @@ describe('ReactDOMFizzServer', () => {
72307253

72317254
expect(recoverableErrors).toEqual(
72327255
__DEV__
7233-
? ['server error']
7256+
? [
7257+
'Switched to client rendering because the server rendering errored:\n\n' +
7258+
'server error',
7259+
]
72347260
: [
72357261
'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
72367262
],

packages/react-dom/src/__tests__/ReactDOMHydrationDiff-test.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,10 +1292,12 @@ describe('ReactDOMServerHydration', () => {
12921292
}
12931293

12941294
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
1295-
[
1296-
"Caught [The server did not finish this Suspense boundary: The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server]",
1297-
]
1298-
`);
1295+
[
1296+
"Caught [Switched to client rendering because the server rendering aborted due to:
1297+
1298+
The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server]",
1299+
]
1300+
`);
12991301
});
13001302

13011303
// @gate __DEV__
@@ -1318,10 +1320,12 @@ describe('ReactDOMServerHydration', () => {
13181320
}
13191321

13201322
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
1321-
[
1322-
"Caught [The server did not finish this Suspense boundary: The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server]",
1323-
]
1324-
`);
1323+
[
1324+
"Caught [Switched to client rendering because the server rendering aborted due to:
1325+
1326+
The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server]",
1327+
]
1328+
`);
13251329
});
13261330
});
13271331

packages/react-reconciler/src/ReactFiberBeginWork.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2659,18 +2659,18 @@ function updateDehydratedSuspenseComponent(
26592659
// TODO: Figure out a better signal than encoding a magic digest value.
26602660
if (!enablePostpone || digest !== 'POSTPONE') {
26612661
let error;
2662-
if (message) {
2662+
if (__DEV__ && message) {
26632663
// eslint-disable-next-line react-internal/prod-error-codes
26642664
error = new Error(message);
26652665
} else {
26662666
error = new Error(
26672667
'The server could not finish this Suspense boundary, likely ' +
2668-
'due to an error during server rendering. Switched to ' +
2669-
'client rendering.',
2668+
'due to an error during server rendering. ' +
2669+
'Switched to client rendering.',
26702670
);
26712671
}
26722672
// Replace the stack with the server stack
2673-
error.stack = stack || '';
2673+
error.stack = (__DEV__ && stack) || '';
26742674
(error: any).digest = digest;
26752675
capturedValue = createCapturedValueFromError(
26762676
error,

packages/react-server/src/ReactFizzServer.js

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,7 @@ function encodeErrorForBoundary(
820820
digest: ?string,
821821
error: mixed,
822822
thrownInfo: ThrownInfo,
823+
wasAborted: boolean,
823824
) {
824825
boundary.errorDigest = digest;
825826
if (__DEV__) {
@@ -838,8 +839,10 @@ function encodeErrorForBoundary(
838839
message = String(error);
839840
stack = null;
840841
}
841-
842-
boundary.errorMessage = message;
842+
const prefix = wasAborted
843+
? 'Switched to client rendering because the server rendering aborted due to:\n\n'
844+
: 'Switched to client rendering because the server rendering errored:\n\n';
845+
boundary.errorMessage = prefix + message;
843846
boundary.errorStack = stack;
844847
boundary.errorComponentStack = thrownInfo.componentStack;
845848
}
@@ -1021,7 +1024,7 @@ function renderSuspenseBoundary(
10211024
} else {
10221025
errorDigest = logRecoverableError(request, error, thrownInfo);
10231026
}
1024-
encodeErrorForBoundary(newBoundary, errorDigest, error, thrownInfo);
1027+
encodeErrorForBoundary(newBoundary, errorDigest, error, thrownInfo, false);
10251028

10261029
untrackBoundary(request, newBoundary);
10271030

@@ -1165,7 +1168,13 @@ function replaySuspenseBoundary(
11651168
} else {
11661169
errorDigest = logRecoverableError(request, error, thrownInfo);
11671170
}
1168-
encodeErrorForBoundary(resumedBoundary, errorDigest, error, thrownInfo);
1171+
encodeErrorForBoundary(
1172+
resumedBoundary,
1173+
errorDigest,
1174+
error,
1175+
thrownInfo,
1176+
false,
1177+
);
11691178

11701179
task.replay.pendingTasks--;
11711180

@@ -2992,7 +3001,7 @@ function erroredTask(
29923001
boundary.pendingTasks--;
29933002
if (boundary.status !== CLIENT_RENDERED) {
29943003
boundary.status = CLIENT_RENDERED;
2995-
encodeErrorForBoundary(boundary, errorDigest, error, errorInfo);
3004+
encodeErrorForBoundary(boundary, errorDigest, error, errorInfo, false);
29963005
untrackBoundary(request, boundary);
29973006

29983007
// Regardless of what happens next, this boundary won't be displayed,
@@ -3039,17 +3048,7 @@ function abortRemainingSuspenseBoundary(
30393048
resumedBoundary.rootSegmentID = rootSegmentID;
30403049

30413050
resumedBoundary.status = CLIENT_RENDERED;
3042-
let errorMessage = error;
3043-
if (__DEV__) {
3044-
const errorPrefix = 'The server did not finish this Suspense boundary: ';
3045-
if (error && typeof error.message === 'string') {
3046-
errorMessage = errorPrefix + error.message;
3047-
} else {
3048-
// eslint-disable-next-line react-internal/safe-string-coercion
3049-
errorMessage = errorPrefix + String(error);
3050-
}
3051-
}
3052-
encodeErrorForBoundary(resumedBoundary, errorDigest, errorMessage, errorInfo);
3051+
encodeErrorForBoundary(resumedBoundary, errorDigest, error, errorInfo, true);
30533052

30543053
if (resumedBoundary.parentFlushed) {
30553054
request.clientRenderedBoundaries.push(resumedBoundary);
@@ -3102,7 +3101,7 @@ function abortRemainingReplayNodes(
31023101
);
31033102
} else if (boundary.status !== CLIENT_RENDERED) {
31043103
boundary.status = CLIENT_RENDERED;
3105-
encodeErrorForBoundary(boundary, errorDigest, error, errorInfo);
3104+
encodeErrorForBoundary(boundary, errorDigest, error, errorInfo, true);
31063105
if (boundary.parentFlushed) {
31073106
request.clientRenderedBoundaries.push(boundary);
31083107
}
@@ -3207,18 +3206,7 @@ function abortTask(task: Task, request: Request, error: mixed): void {
32073206
} else {
32083207
errorDigest = logRecoverableError(request, error, errorInfo);
32093208
}
3210-
let errorMessage = error;
3211-
if (__DEV__) {
3212-
const errorPrefix =
3213-
'The server did not finish this Suspense boundary: ';
3214-
if (error && typeof error.message === 'string') {
3215-
errorMessage = errorPrefix + error.message;
3216-
} else {
3217-
// eslint-disable-next-line react-internal/safe-string-coercion
3218-
errorMessage = errorPrefix + String(error);
3219-
}
3220-
}
3221-
encodeErrorForBoundary(boundary, errorDigest, errorMessage, errorInfo);
3209+
encodeErrorForBoundary(boundary, errorDigest, error, errorInfo, true);
32223210

32233211
untrackBoundary(request, boundary);
32243212

0 commit comments

Comments
 (0)