diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js index 87f72814ac96a..9987343b90f3b 100644 --- a/packages/react-noop-renderer/src/createReactNoop.js +++ b/packages/react-noop-renderer/src/createReactNoop.js @@ -533,6 +533,13 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { newChildren: Array, ): void { container.pendingChildren = newChildren; + if ( + newChildren.length === 1 && + newChildren[0].text === 'Error when completing root' + ) { + // Trigger an error for testing purposes + throw Error('Error when completing root'); + } }, replaceContainerChildren( diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 116bb2e99cf60..02d1bec97ff8b 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -1285,6 +1285,13 @@ function handleError(root, thrownValue) { // boundary. workInProgressRootExitStatus = RootFatalErrored; workInProgressRootFatalError = thrownValue; + // Set `workInProgress` to null. This represents advancing to the next + // sibling, or the parent if there are no siblings. But since the root + // has no siblings nor a parent, we set it to null. Usually this is + // handled by `completeUnitOfWork` or `unwindWork`, but since we're + // interntionally not calling those, we need set it here. + // TODO: Consider calling `unwindWork` to pop the contexts. + workInProgress = null; return null; } diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js index bcb74b6ea07f8..6bea104b78db5 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js @@ -1658,4 +1658,16 @@ describe('ReactIncrementalErrorHandling', () => { 'Please update the following components: Provider', ]); }); + + if (global.__PERSISTENT__) { + it('regression test: should fatal if error is thrown at the root', () => { + const root = ReactNoop.createRoot(); + root.render('Error when completing root'); + expect(Scheduler).toFlushAndThrow('Error when completing root'); + + const blockingRoot = ReactNoop.createBlockingRoot(); + blockingRoot.render('Error when completing root'); + expect(Scheduler).toFlushAndThrow('Error when completing root'); + }); + } });