Skip to content

Commit

Permalink
Set the current fiber to the source of the error during error reporti…
Browse files Browse the repository at this point in the history
…ng (#29044)

This lets us expose the component stack to the error reporting that
happens here as `console.error` patching. Now if you just call
`console.error` in the error handlers it'll get the component stack
added to the end by React DevTools.

However, unfortunately this happens a little too late so the Fiber will
be disconnected with its `.return` pointer set to null already. So it'll
be too late to extract a parent component stack from but you can at
least get the stack from source to error boundary. To work around this I
manually add the parent component stack in our default handlers when
owner stacks are off. We could potentially fix this but you can also
just include it yourself if you're calling `console.error` and it's not
a problem for owner stacks.

This is not a problem for owner stacks because we'll still have those
and so for those just calling `console.error` just works. However, the
main feature is that by letting React add them, we can switch to using
native error stacks when available.

DiffTrain build for [2e540e2](2e540e2)
  • Loading branch information
sebmarkbage committed May 23, 2024
1 parent 89d5de9 commit 2de2c20
Show file tree
Hide file tree
Showing 12 changed files with 353 additions and 75 deletions.
2 changes: 1 addition & 1 deletion compiled/facebook-www/REVISION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2e3e6a9b1cc97ec91248be74565e7ccbf6946067
2e540e22b2b4038a278b2875306976b016fb31a9
16 changes: 15 additions & 1 deletion compiled/facebook-www/ReactART-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function _assertThisInitialized(self) {
return self;
}

var ReactVersion = '19.0.0-www-classic-53ce7a77';
var ReactVersion = '19.0.0-www-classic-15c5a6dc';

var LegacyRoot = 0;
var ConcurrentRoot = 1;
Expand Down Expand Up @@ -12491,7 +12491,11 @@ function createRootErrorUpdate(root, errorInfo, lane) {
};

update.callback = function () {
var prevFiber = getCurrentFiber(); // should just be the root

setCurrentDebugFiberInDEV(errorInfo.source);
logUncaughtError(root, errorInfo);
setCurrentDebugFiberInDEV(prevFiber);
};

return update;
Expand All @@ -12518,7 +12522,11 @@ function initializeClassErrorUpdate(update, root, fiber, errorInfo) {
markFailedErrorBoundaryForHotReloading(fiber);
}

var prevFiber = getCurrentFiber(); // should be the error boundary

setCurrentDebugFiberInDEV(errorInfo.source);
logCaughtError(root, fiber, errorInfo);
setCurrentDebugFiberInDEV(prevFiber);
};
}

Expand All @@ -12531,7 +12539,11 @@ function initializeClassErrorUpdate(update, root, fiber, errorInfo) {
markFailedErrorBoundaryForHotReloading(fiber);
}

var prevFiber = getCurrentFiber(); // should be the error boundary

setCurrentDebugFiberInDEV(errorInfo.source);
logCaughtError(root, fiber, errorInfo);
setCurrentDebugFiberInDEV(prevFiber);

if (typeof getDerivedStateFromError !== 'function') {
// To preserve the preexisting retry behavior of error boundaries,
Expand Down Expand Up @@ -24159,7 +24171,9 @@ function commitRootImpl(root, recoverableErrors, transitions, didIncludeRenderPh
for (var i = 0; i < recoverableErrors.length; i++) {
var recoverableError = recoverableErrors[i];
var errorInfo = makeErrorInfo(recoverableError.stack);
setCurrentDebugFiberInDEV(recoverableError.source);
onRecoverableError(recoverableError.value, errorInfo);
resetCurrentDebugFiberInDEV();
}
} // If the passive effects are the result of a discrete render, flush them
// synchronously at the end of the current task so that the result is
Expand Down
16 changes: 15 additions & 1 deletion compiled/facebook-www/ReactART-dev.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function _assertThisInitialized(self) {
return self;
}

var ReactVersion = '19.0.0-www-modern-d3cf6c2c';
var ReactVersion = '19.0.0-www-modern-1bbec70f';

var LegacyRoot = 0;
var ConcurrentRoot = 1;
Expand Down Expand Up @@ -12256,7 +12256,11 @@ function createRootErrorUpdate(root, errorInfo, lane) {
};

update.callback = function () {
var prevFiber = getCurrentFiber(); // should just be the root

setCurrentDebugFiberInDEV(errorInfo.source);
logUncaughtError(root, errorInfo);
setCurrentDebugFiberInDEV(prevFiber);
};

return update;
Expand All @@ -12283,7 +12287,11 @@ function initializeClassErrorUpdate(update, root, fiber, errorInfo) {
markFailedErrorBoundaryForHotReloading(fiber);
}

var prevFiber = getCurrentFiber(); // should be the error boundary

setCurrentDebugFiberInDEV(errorInfo.source);
logCaughtError(root, fiber, errorInfo);
setCurrentDebugFiberInDEV(prevFiber);
};
}

Expand All @@ -12296,7 +12304,11 @@ function initializeClassErrorUpdate(update, root, fiber, errorInfo) {
markFailedErrorBoundaryForHotReloading(fiber);
}

var prevFiber = getCurrentFiber(); // should be the error boundary

setCurrentDebugFiberInDEV(errorInfo.source);
logCaughtError(root, fiber, errorInfo);
setCurrentDebugFiberInDEV(prevFiber);

if (typeof getDerivedStateFromError !== 'function') {
// To preserve the preexisting retry behavior of error boundaries,
Expand Down Expand Up @@ -23513,7 +23525,9 @@ function commitRootImpl(root, recoverableErrors, transitions, didIncludeRenderPh
for (var i = 0; i < recoverableErrors.length; i++) {
var recoverableError = recoverableErrors[i];
var errorInfo = makeErrorInfo(recoverableError.stack);
setCurrentDebugFiberInDEV(recoverableError.source);
onRecoverableError(recoverableError.value, errorInfo);
resetCurrentDebugFiberInDEV();
}
} // If the passive effects are the result of a discrete render, flush them
// synchronously at the end of the current task so that the result is
Expand Down
49 changes: 40 additions & 9 deletions compiled/facebook-www/ReactDOM-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -16244,22 +16244,39 @@ function defaultOnUncaughtError(error, errorInfo) {
reportGlobalError(error);

{
var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : '';
var componentNameMessage = componentName ? "An error occurred in the <" + componentName + "> component:" : 'An error occurred in one of your React components:';
console['warn']('%s\n%s\n\n%s', componentNameMessage, componentStack || '', 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.');
var componentNameMessage = componentName ? "An error occurred in the <" + componentName + "> component." : 'An error occurred in one of your React components.';
var errorBoundaryMessage = 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.';

{
// The current Fiber is disconnected at this point which means that console printing
// cannot add a component stack since it terminates at the deletion node. This is not
// a problem for owner stacks which are not disconnected but for the parent component
// stacks we need to use the snapshot we've previously extracted.
var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; // Don't transform to our wrapper

console['warn']('%s\n\n%s\n%s', componentNameMessage, errorBoundaryMessage, componentStack);
}
}
}
function defaultOnCaughtError(error, errorInfo) {
function defaultOnCaughtError(error$1, errorInfo) {
// Overriding this can silence these warnings e.g. for tests.
// See https://github.com/facebook/react/pull/13384
// Caught by error boundary
{
var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : '';
var componentNameMessage = componentName ? "The above error occurred in the <" + componentName + "> component:" : 'The above error occurred in one of your React components:'; // In development, we provide our own message which includes the component stack
var componentNameMessage = componentName ? "The above error occurred in the <" + componentName + "> component." : 'The above error occurred in one of your React components.'; // In development, we provide our own message which includes the component stack
// in addition to the error.
// Don't transform to our wrapper

console['error']('%o\n\n%s\n%s\n\n%s', error, componentNameMessage, componentStack, "React will try to recreate this component tree from scratch " + ("using the error boundary you provided, " + (errorBoundaryName || 'Anonymous') + "."));
var recreateMessage = "React will try to recreate this component tree from scratch " + ("using the error boundary you provided, " + (errorBoundaryName || 'Anonymous') + ".");

{
// The current Fiber is disconnected at this point which means that console printing
// cannot add a component stack since it terminates at the deletion node. This is not
// a problem for owner stacks which are not disconnected but for the parent component
// stacks we need to use the snapshot we've previously extracted.
var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; // Don't transform to our wrapper

console['error']('%o\n\n%s\n\n%s\n%s', error$1, componentNameMessage, recreateMessage, componentStack);
}
}
}
function defaultOnRecoverableError(error, errorInfo) {
Expand Down Expand Up @@ -16331,7 +16348,11 @@ function createRootErrorUpdate(root, errorInfo, lane) {
};

update.callback = function () {
var prevFiber = getCurrentFiber(); // should just be the root

setCurrentDebugFiberInDEV(errorInfo.source);
logUncaughtError(root, errorInfo);
setCurrentDebugFiberInDEV(prevFiber);
};

return update;
Expand All @@ -16358,7 +16379,11 @@ function initializeClassErrorUpdate(update, root, fiber, errorInfo) {
markFailedErrorBoundaryForHotReloading(fiber);
}

var prevFiber = getCurrentFiber(); // should be the error boundary

setCurrentDebugFiberInDEV(errorInfo.source);
logCaughtError(root, fiber, errorInfo);
setCurrentDebugFiberInDEV(prevFiber);
};
}

Expand All @@ -16371,7 +16396,11 @@ function initializeClassErrorUpdate(update, root, fiber, errorInfo) {
markFailedErrorBoundaryForHotReloading(fiber);
}

var prevFiber = getCurrentFiber(); // should be the error boundary

setCurrentDebugFiberInDEV(errorInfo.source);
logCaughtError(root, fiber, errorInfo);
setCurrentDebugFiberInDEV(prevFiber);

if (typeof getDerivedStateFromError !== 'function') {
// To preserve the preexisting retry behavior of error boundaries,
Expand Down Expand Up @@ -28862,7 +28891,9 @@ function commitRootImpl(root, recoverableErrors, transitions, didIncludeRenderPh
for (var i = 0; i < recoverableErrors.length; i++) {
var recoverableError = recoverableErrors[i];
var errorInfo = makeErrorInfo(recoverableError.stack);
setCurrentDebugFiberInDEV(recoverableError.source);
onRecoverableError(recoverableError.value, errorInfo);
resetCurrentDebugFiberInDEV();
}
} // If the passive effects are the result of a discrete render, flush them
// synchronously at the end of the current task so that the result is
Expand Down Expand Up @@ -30852,7 +30883,7 @@ identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, transition
return root;
}

var ReactVersion = '19.0.0-www-classic-d3c0ad7c';
var ReactVersion = '19.0.0-www-classic-6551c42e';

function createPortal$1(children, containerInfo, // TODO: figure out the API for cross-renderer implementation.
implementation) {
Expand Down
49 changes: 40 additions & 9 deletions compiled/facebook-www/ReactDOM-dev.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -15961,22 +15961,39 @@ function defaultOnUncaughtError(error, errorInfo) {
reportGlobalError(error);

{
var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : '';
var componentNameMessage = componentName ? "An error occurred in the <" + componentName + "> component:" : 'An error occurred in one of your React components:';
console['warn']('%s\n%s\n\n%s', componentNameMessage, componentStack || '', 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.');
var componentNameMessage = componentName ? "An error occurred in the <" + componentName + "> component." : 'An error occurred in one of your React components.';
var errorBoundaryMessage = 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.';

{
// The current Fiber is disconnected at this point which means that console printing
// cannot add a component stack since it terminates at the deletion node. This is not
// a problem for owner stacks which are not disconnected but for the parent component
// stacks we need to use the snapshot we've previously extracted.
var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; // Don't transform to our wrapper

console['warn']('%s\n\n%s\n%s', componentNameMessage, errorBoundaryMessage, componentStack);
}
}
}
function defaultOnCaughtError(error, errorInfo) {
function defaultOnCaughtError(error$1, errorInfo) {
// Overriding this can silence these warnings e.g. for tests.
// See https://github.com/facebook/react/pull/13384
// Caught by error boundary
{
var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : '';
var componentNameMessage = componentName ? "The above error occurred in the <" + componentName + "> component:" : 'The above error occurred in one of your React components:'; // In development, we provide our own message which includes the component stack
var componentNameMessage = componentName ? "The above error occurred in the <" + componentName + "> component." : 'The above error occurred in one of your React components.'; // In development, we provide our own message which includes the component stack
// in addition to the error.
// Don't transform to our wrapper

console['error']('%o\n\n%s\n%s\n\n%s', error, componentNameMessage, componentStack, "React will try to recreate this component tree from scratch " + ("using the error boundary you provided, " + (errorBoundaryName || 'Anonymous') + "."));
var recreateMessage = "React will try to recreate this component tree from scratch " + ("using the error boundary you provided, " + (errorBoundaryName || 'Anonymous') + ".");

{
// The current Fiber is disconnected at this point which means that console printing
// cannot add a component stack since it terminates at the deletion node. This is not
// a problem for owner stacks which are not disconnected but for the parent component
// stacks we need to use the snapshot we've previously extracted.
var componentStack = errorInfo.componentStack != null ? errorInfo.componentStack : ''; // Don't transform to our wrapper

console['error']('%o\n\n%s\n\n%s\n%s', error$1, componentNameMessage, recreateMessage, componentStack);
}
}
}
function defaultOnRecoverableError(error, errorInfo) {
Expand Down Expand Up @@ -16048,7 +16065,11 @@ function createRootErrorUpdate(root, errorInfo, lane) {
};

update.callback = function () {
var prevFiber = getCurrentFiber(); // should just be the root

setCurrentDebugFiberInDEV(errorInfo.source);
logUncaughtError(root, errorInfo);
setCurrentDebugFiberInDEV(prevFiber);
};

return update;
Expand All @@ -16075,7 +16096,11 @@ function initializeClassErrorUpdate(update, root, fiber, errorInfo) {
markFailedErrorBoundaryForHotReloading(fiber);
}

var prevFiber = getCurrentFiber(); // should be the error boundary

setCurrentDebugFiberInDEV(errorInfo.source);
logCaughtError(root, fiber, errorInfo);
setCurrentDebugFiberInDEV(prevFiber);
};
}

Expand All @@ -16088,7 +16113,11 @@ function initializeClassErrorUpdate(update, root, fiber, errorInfo) {
markFailedErrorBoundaryForHotReloading(fiber);
}

var prevFiber = getCurrentFiber(); // should be the error boundary

setCurrentDebugFiberInDEV(errorInfo.source);
logCaughtError(root, fiber, errorInfo);
setCurrentDebugFiberInDEV(prevFiber);

if (typeof getDerivedStateFromError !== 'function') {
// To preserve the preexisting retry behavior of error boundaries,
Expand Down Expand Up @@ -28113,7 +28142,9 @@ function commitRootImpl(root, recoverableErrors, transitions, didIncludeRenderPh
for (var i = 0; i < recoverableErrors.length; i++) {
var recoverableError = recoverableErrors[i];
var errorInfo = makeErrorInfo(recoverableError.stack);
setCurrentDebugFiberInDEV(recoverableError.source);
onRecoverableError(recoverableError.value, errorInfo);
resetCurrentDebugFiberInDEV();
}
} // If the passive effects are the result of a discrete render, flush them
// synchronously at the end of the current task so that the result is
Expand Down Expand Up @@ -30027,7 +30058,7 @@ identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, transition
return root;
}

var ReactVersion = '19.0.0-www-modern-533bc87e';
var ReactVersion = '19.0.0-www-modern-c6c71924';

function createPortal$1(children, containerInfo, // TODO: figure out the API for cross-renderer implementation.
implementation) {
Expand Down
Loading

0 comments on commit 2de2c20

Please sign in to comment.