diff --git a/packages/react-devtools-shared/src/__tests__/profilerStore-test.js b/packages/react-devtools-shared/src/__tests__/profilerStore-test.js
index 06ce6a9dc4c8f..7f553bed82e8b 100644
--- a/packages/react-devtools-shared/src/__tests__/profilerStore-test.js
+++ b/packages/react-devtools-shared/src/__tests__/profilerStore-test.js
@@ -221,4 +221,24 @@ describe('ProfilerStore', () => {
expect(data.commitData).toHaveLength(1);
expect(data.operations).toHaveLength(1);
});
+
+ it('should not throw while initializing context values for Fibers within a not-yet-mounted subtree', () => {
+ const promise = new Promise(resolve => {});
+ const SuspendingView = () => {
+ throw promise;
+ };
+
+ const App = () => {
+ return (
+
+
+
+ );
+ };
+
+ const container = document.createElement('div');
+
+ utils.act(() => legacyRender(, container));
+ utils.act(() => store.profilerStore.startProfiling());
+ });
});
diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js
index 0f7b15cd019b9..9a60fe42376a2 100644
--- a/packages/react-devtools-shared/src/backend/renderer.js
+++ b/packages/react-devtools-shared/src/backend/renderer.js
@@ -1347,11 +1347,19 @@ export function attach(
// Fibers only store the current context value,
// so we need to track them separately in order to determine changed keys.
function crawlToInitializeContextsMap(fiber: Fiber) {
- updateContextsForFiber(fiber);
- let current = fiber.child;
- while (current !== null) {
- crawlToInitializeContextsMap(current);
- current = current.sibling;
+ const id = getFiberIDUnsafe(fiber);
+
+ // Not all Fibers in the subtree have mounted yet.
+ // For example, Offscreen (hidden) or Suspense (suspended) subtrees won't yet be tracked.
+ // We can safely skip these subtrees.
+ if (id !== null) {
+ updateContextsForFiber(fiber);
+
+ let current = fiber.child;
+ while (current !== null) {
+ crawlToInitializeContextsMap(current);
+ current = current.sibling;
+ }
}
}