diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
index 13774ec2de075..a42056ab24922 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
@@ -796,6 +796,73 @@ describe('ReactDOMFizzServer', () => {
);
});
+ // @gate experimental
+ it('should recover the outer context when an error happens inside a provider', async () => {
+ const ContextA = React.createContext('A0');
+ const ContextB = React.createContext('B0');
+
+ function PrintA() {
+ return (
+ {value => }
+ );
+ }
+
+ class PrintB extends React.Component {
+ static contextType = ContextB;
+ render() {
+ return ;
+ }
+ }
+
+ function Throws() {
+ const value = React.useContext(ContextA);
+ throw new Error(value);
+ }
+
+ const loggedErrors = [];
+ await act(async () => {
+ const {startWriting} = ReactDOMFizzServer.pipeToNodeWritable(
+
+
+
+
+
+
+
+ }>
+
+
+
+
+
+
+
+
+
,
+ writable,
+ {
+ onError(x) {
+ loggedErrors.push(x);
+ },
+ },
+ );
+ startWriting();
+ });
+ expect(loggedErrors.length).toBe(1);
+ expect(loggedErrors[0].message).toEqual('A0.1.1');
+ expect(getVisibleChildren(container)).toEqual(
+
+ A0
+
+ Loading...B0
+
+ A0
+
,
+ );
+ });
+
// @gate experimental
it('client renders a boundary if it errors before finishing the fallback', async () => {
function App({isClient}) {
diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js
index 9409b57bbbf18..d51ad44ed64e3 100644
--- a/packages/react-server/src/ReactFizzServer.js
+++ b/packages/react-server/src/ReactFizzServer.js
@@ -1174,6 +1174,13 @@ function renderNode(request: Request, task: Task, node: ReactNodeList): void {
// Restore all active ReactContexts to what they were before.
switchContext(previousContext);
} else {
+ // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+ task.blockedSegment.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ // Restore all active ReactContexts to what they were before.
+ switchContext(previousContext);
// We assume that we don't need the correct context.
// Let's terminate the rest of the tree and don't render any siblings.
throw x;