diff --git a/.github/workflows/discord_notify.yml b/.github/workflows/discord_notify.yml
new file mode 100644
index 0000000000000..46481691b975d
--- /dev/null
+++ b/.github/workflows/discord_notify.yml
@@ -0,0 +1,22 @@
+name: Discord Notify
+
+on:
+  pull_request:
+    types: [ labeled ]
+    
+jobs:
+  notify:
+      if: ${{ github.event.label.name == 'React Core Team' }}
+      runs-on: ubuntu-latest
+      steps:
+        - name: Discord Webhook Action
+          uses: tsickert/discord-webhook@v6.0.0
+          with:
+              webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
+              embed-author-name: ${{ github.event.pull_request.user.login }}
+              embed-author-url: ${{ github.event.pull_request.user.html_url }}
+              embed-author-icon-url: ${{ github.event.pull_request.user.avatar_url }}
+              embed-title: '#${{ github.event.number }}: ${{ github.event.pull_request.title }}'
+              embed-description: ${{ github.event.pull_request.body }}
+              embed-url: ${{ github.event.pull_request.html_url }}
+            
\ No newline at end of file
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js
index 7a52e9d0dd0a8..be5ff44b8cd12 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js
@@ -16,6 +16,7 @@ let React;
 let ReactDOM;
 let ReactDOMClient;
 let ReactDOMServer;
+let assertConsoleErrorDev;
 
 function initModules() {
   // Reset warning cache.
@@ -24,6 +25,7 @@ function initModules() {
   ReactDOM = require('react-dom');
   ReactDOMClient = require('react-dom/client');
   ReactDOMServer = require('react-dom/server');
+  assertConsoleErrorDev = require('internal-test-utils').assertConsoleErrorDev;
 
   // Make them available to the helpers.
   return {
@@ -39,6 +41,13 @@ describe('ReactDOMServerIntegration', () => {
   beforeEach(() => {
     resetModules();
   });
+  afterEach(() => {
+    // TODO: This is a hack because expectErrors does not restore mock,
+    // however fixing it requires a major refactor to all these tests.
+    if (console.error.mockClear) {
+      console.error.mockRestore();
+    }
+  });
 
   describe('property to attribute mapping', function () {
     describe('string properties', function () {
@@ -633,14 +642,15 @@ describe('ReactDOMServerIntegration', () => {
         // However this particular warning fires only when creating
         // DOM nodes on the client side. We force it to fire early
         // so that it gets deduplicated later, and doesn't fail the test.
-        expect(() => {
-          ReactDOM.flushSync(() => {
-            const root = ReactDOMClient.createRoot(
-              document.createElement('div'),
-            );
-            root.render();
-          });
-        }).toErrorDev('The tag  is unrecognized in this browser.');
+        ReactDOM.flushSync(() => {
+          const root = ReactDOMClient.createRoot(document.createElement('div'));
+          root.render();
+        });
+        assertConsoleErrorDev([
+          'The tag  is unrecognized in this browser. ' +
+            'If you meant to render a React component, start its name with an uppercase letter.\n' +
+            '    in nonstandard (at **)',
+        ]);
 
         const e = await render();
         expect(e.getAttribute('foo')).toBe('bar');
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js
index 0fcc314d39a05..50d189cc0860f 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js
@@ -18,6 +18,7 @@ let React;
 let ReactDOM;
 let ReactDOMClient;
 let ReactDOMServer;
+let assertConsoleErrorDev;
 
 function initModules() {
   jest.resetModules();
@@ -25,6 +26,7 @@ function initModules() {
   ReactDOM = require('react-dom');
   ReactDOMClient = require('react-dom/client');
   ReactDOMServer = require('react-dom/server');
+  assertConsoleErrorDev = require('internal-test-utils').assertConsoleErrorDev;
 
   // Make them available to the helpers.
   return {
@@ -48,6 +50,14 @@ describe('ReactDOMServerIntegration', () => {
     resetModules();
   });
 
+  afterEach(() => {
+    // TODO: This is a hack because expectErrors does not restore mock,
+    // however fixing it requires a major refactor to all these tests.
+    if (console.error.mockClear) {
+      console.error.mockRestore();
+    }
+  });
+
   describe('elements and children', function () {
     function expectNode(node, type, value) {
       expect(node).not.toBe(null);
@@ -134,15 +144,15 @@ describe('ReactDOMServerIntegration', () => {
         // However this particular warning fires only when creating
         // DOM nodes on the client side. We force it to fire early
         // so that it gets deduplicated later, and doesn't fail the test.
-        expect(() => {
-          ReactDOM.flushSync(() => {
-            const root = ReactDOMClient.createRoot(
-              document.createElement('div'),
-            );
-
-            root.render();
-          });
-        }).toErrorDev('The tag  is unrecognized in this browser.');
+        ReactDOM.flushSync(() => {
+          const root = ReactDOMClient.createRoot(document.createElement('div'));
+          root.render();
+        });
+        assertConsoleErrorDev([
+          'The tag  is unrecognized in this browser. ' +
+            'If you meant to render a React component, start its name with an uppercase letter.\n' +
+            '    in nonstandard (at **)',
+        ]);
 
         const e = await render(Text);
         expect(e.tagName).toBe('NONSTANDARD');
@@ -984,16 +994,17 @@ describe('ReactDOMServerIntegration', () => {
         'object',
         async render => {
           let EmptyComponent = {};
-          expect(() => {
-            EmptyComponent = ;
-          }).toErrorDev(
+          EmptyComponent = ;
+          assertConsoleErrorDev(
             gate(flags => flags.enableOwnerStacks)
               ? []
-              : 'React.jsx: type is invalid -- expected a string ' +
-                  '(for built-in components) or a class/function (for composite ' +
-                  'components) but got: object. You likely forgot to export your ' +
-                  "component from the file it's defined in, or you might have mixed up " +
-                  'default and named imports.',
+              : [
+                  'React.jsx: type is invalid -- expected a string ' +
+                    '(for built-in components) or a class/function (for composite ' +
+                    'components) but got: object. You likely forgot to export your ' +
+                    "component from the file it's defined in, or you might have mixed up " +
+                    'default and named imports.',
+                ],
             {withoutStack: true},
           );
           await render(EmptyComponent);
@@ -1010,14 +1021,15 @@ describe('ReactDOMServerIntegration', () => {
         'null',
         async render => {
           let NullComponent = null;
-          expect(() => {
-            NullComponent = ;
-          }).toErrorDev(
+          NullComponent = ;
+          assertConsoleErrorDev(
             gate(flags => flags.enableOwnerStacks)
               ? []
-              : 'React.jsx: type is invalid -- expected a string ' +
-                  '(for built-in components) or a class/function (for composite ' +
-                  'components) but got: null.',
+              : [
+                  'React.jsx: type is invalid -- expected a string ' +
+                    '(for built-in components) or a class/function (for composite ' +
+                    'components) but got: null.',
+                ],
             {withoutStack: true},
           );
           await render(NullComponent);
@@ -1030,16 +1042,17 @@ describe('ReactDOMServerIntegration', () => {
         'undefined',
         async render => {
           let UndefinedComponent = undefined;
-          expect(() => {
-            UndefinedComponent = ;
-          }).toErrorDev(
+          UndefinedComponent = ;
+          assertConsoleErrorDev(
             gate(flags => flags.enableOwnerStacks)
               ? []
-              : 'React.jsx: type is invalid -- expected a string ' +
-                  '(for built-in components) or a class/function (for composite ' +
-                  'components) but got: undefined. You likely forgot to export your ' +
-                  "component from the file it's defined in, or you might have mixed up " +
-                  'default and named imports.',
+              : [
+                  'React.jsx: type is invalid -- expected a string ' +
+                    '(for built-in components) or a class/function (for composite ' +
+                    'components) but got: undefined. You likely forgot to export your ' +
+                    "component from the file it's defined in, or you might have mixed up " +
+                    'default and named imports.',
+                ],
             {withoutStack: true},
           );
 
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js
index 08551150a7a87..3fafff04170b7 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js
@@ -16,6 +16,7 @@ let PropTypes;
 let React;
 let ReactDOMClient;
 let ReactDOMServer;
+let assertConsoleErrorDev;
 
 function initModules() {
   // Reset warning cache.
@@ -24,6 +25,7 @@ function initModules() {
   React = require('react');
   ReactDOMClient = require('react-dom/client');
   ReactDOMServer = require('react-dom/server');
+  assertConsoleErrorDev = require('internal-test-utils').assertConsoleErrorDev;
 
   // Make them available to the helpers.
   return {
@@ -43,6 +45,13 @@ describe('ReactDOMServerIntegration', () => {
   beforeEach(() => {
     resetModules();
   });
+  afterEach(() => {
+    // TODO: This is a hack because expectErrors does not restore mock,
+    // however fixing it requires a major refactor to all these tests.
+    if (console.error.mockClear) {
+      console.error.mockRestore();
+    }
+  });
 
   describe('legacy context', function () {
     // The `itRenders` test abstraction doesn't work with @gate so we have
@@ -344,12 +353,11 @@ describe('ReactDOMServerIntegration', () => {
         }
       }
 
-      expect(() => {
-        ReactDOMServer.renderToString();
-      }).toErrorDev(
+      ReactDOMServer.renderToString();
+      assertConsoleErrorDev([
         'MyComponent.getChildContext(): childContextTypes must be defined in order to use getChildContext().\n' +
           '    in MyComponent (at **)',
-      );
+      ]);
     });
   });
 });
diff --git a/packages/react-reconciler/src/__tests__/Activity-test.js b/packages/react-reconciler/src/__tests__/Activity-test.js
index cc5c4b921ce98..191e72e3cb14d 100644
--- a/packages/react-reconciler/src/__tests__/Activity-test.js
+++ b/packages/react-reconciler/src/__tests__/Activity-test.js
@@ -14,6 +14,7 @@ let startTransition;
 let waitForPaint;
 let waitFor;
 let assertLog;
+let assertConsoleErrorDev;
 
 describe('Activity', () => {
   beforeEach(() => {
@@ -37,6 +38,7 @@ describe('Activity', () => {
     waitForPaint = InternalTestUtils.waitForPaint;
     waitFor = InternalTestUtils.waitFor;
     assertLog = InternalTestUtils.assertLog;
+    assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
   });
 
   function Text(props) {
@@ -784,11 +786,14 @@ describe('Activity', () => {
       // would be null because it was nulled out when it was deleted, but there
       // was no null check before we accessed it. A weird edge case but we must
       // account for it.
-      expect(() => {
-        setState('Updated');
-      }).toErrorDev(
-        "Can't perform a React state update on a component that hasn't mounted yet",
-      );
+      setState('Updated');
+      assertConsoleErrorDev([
+        "Can't perform a React state update on a component that hasn't mounted yet. " +
+          'This indicates that you have a side-effect in your render function that ' +
+          'asynchronously later calls tries to update the component. ' +
+          'Move this work to useEffect instead.\n' +
+          '    in Child (at **)',
+      ]);
     });
     expect(root).toMatchRenderedOutput(null);
   });
diff --git a/packages/react-reconciler/src/__tests__/ReactActWarnings-test.js b/packages/react-reconciler/src/__tests__/ReactActWarnings-test.js
index 561741c108622..82827406557dc 100644
--- a/packages/react-reconciler/src/__tests__/ReactActWarnings-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactActWarnings-test.js
@@ -18,6 +18,7 @@ let Suspense;
 let startTransition;
 let getCacheForType;
 let caches;
+let assertConsoleErrorDev;
 
 // These tests are mostly concerned with concurrent roots. The legacy root
 // behavior is covered by other older test suites and is unchanged from
@@ -38,6 +39,7 @@ describe('act warnings', () => {
     const InternalTestUtils = require('internal-test-utils');
     waitForAll = InternalTestUtils.waitForAll;
     assertLog = InternalTestUtils.assertLog;
+    assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
   });
 
   function createTextCache() {
@@ -171,9 +173,21 @@ describe('act warnings', () => {
 
     // Flag is true. Warn.
     await withActEnvironment(true, async () => {
-      expect(() => setState(2)).toErrorDev(
-        'An update to App inside a test was not wrapped in act',
-      );
+      setState(2);
+      assertConsoleErrorDev([
+        'An update to App inside a test was not wrapped in act(...).\n' +
+          '\n' +
+          'When testing, code that causes React state updates should be wrapped into act(...):\n' +
+          '\n' +
+          'act(() => {\n' +
+          '  /* fire events that update state */\n' +
+          '});\n' +
+          '/* assert on the output */\n' +
+          '\n' +
+          "This ensures that you're testing the behavior the user would see in the browser. " +
+          'Learn more at https://react.dev/link/wrap-tests-with-act\n' +
+          '    in App (at **)',
+      ]);
       await waitForAll([2]);
       expect(root).toMatchRenderedOutput('2');
     });
@@ -202,12 +216,11 @@ describe('act warnings', () => {
 
     // Default behavior. Flag is undefined. Warn.
     expect(global.IS_REACT_ACT_ENVIRONMENT).toBe(undefined);
-    expect(() => {
-      act(() => {
-        setState(1);
-      });
-    }).toErrorDev(
-      'The current testing environment is not configured to support act(...)',
+    act(() => {
+      setState(1);
+    });
+    assertConsoleErrorDev(
+      ['The current testing environment is not configured to support act(...)'],
       {withoutStack: true},
     );
     assertLog([1]);
@@ -224,12 +237,13 @@ describe('act warnings', () => {
 
     // Flag is false. Warn.
     await withActEnvironment(false, () => {
-      expect(() => {
-        act(() => {
-          setState(1);
-        });
-      }).toErrorDev(
-        'The current testing environment is not configured to support act(...)',
+      act(() => {
+        setState(1);
+      });
+      assertConsoleErrorDev(
+        [
+          'The current testing environment is not configured to support act(...)',
+        ],
         {withoutStack: true},
       );
       assertLog([1]);
@@ -240,10 +254,23 @@ describe('act warnings', () => {
   it('warns if root update is not wrapped', async () => {
     await withActEnvironment(true, () => {
       const root = ReactNoop.createRoot();
-      expect(() => root.render('Hi')).toErrorDev(
-        // TODO: Better error message that doesn't make it look like "Root" is
-        // the name of a custom component
-        'An update to Root inside a test was not wrapped in act(...)',
+      root.render('Hi');
+      assertConsoleErrorDev(
+        [
+          // TODO: Better error message that doesn't make it look like "Root" is
+          // the name of a custom component
+          'An update to Root inside a test was not wrapped in act(...).\n' +
+            '\n' +
+            'When testing, code that causes React state updates should be wrapped into act(...):\n' +
+            '\n' +
+            'act(() => {\n' +
+            '  /* fire events that update state */\n' +
+            '});\n' +
+            '/* assert on the output */\n' +
+            '\n' +
+            "This ensures that you're testing the behavior the user would see in the browser. " +
+            'Learn more at https://react.dev/link/wrap-tests-with-act',
+        ],
         {withoutStack: true},
       );
     });
@@ -265,9 +292,21 @@ describe('act warnings', () => {
       act(() => {
         root.render();
       });
-      expect(() => app.setState({count: 1})).toErrorDev(
-        'An update to App inside a test was not wrapped in act(...)',
-      );
+      app.setState({count: 1});
+      assertConsoleErrorDev([
+        'An update to App inside a test was not wrapped in act(...).\n' +
+          '\n' +
+          'When testing, code that causes React state updates should be wrapped into act(...):\n' +
+          '\n' +
+          'act(() => {\n' +
+          '  /* fire events that update state */\n' +
+          '});\n' +
+          '/* assert on the output */\n' +
+          '\n' +
+          "This ensures that you're testing the behavior the user would see in the browser. " +
+          'Learn more at https://react.dev/link/wrap-tests-with-act\n' +
+          '    in App (at **)',
+      ]);
     });
   });
 
@@ -288,9 +327,21 @@ describe('act warnings', () => {
 
       // Even though this update is synchronous, we should still fire a warning,
       // because it could have spawned additional asynchronous work
-      expect(() => ReactNoop.flushSync(() => setState(1))).toErrorDev(
-        'An update to App inside a test was not wrapped in act(...)',
-      );
+      ReactNoop.flushSync(() => setState(1));
+      assertConsoleErrorDev([
+        'An update to App inside a test was not wrapped in act(...).\n' +
+          '\n' +
+          'When testing, code that causes React state updates should be wrapped into act(...):\n' +
+          '\n' +
+          'act(() => {\n' +
+          '  /* fire events that update state */\n' +
+          '});\n' +
+          '/* assert on the output */\n' +
+          '\n' +
+          "This ensures that you're testing the behavior the user would see in the browser. " +
+          'Learn more at https://react.dev/link/wrap-tests-with-act\n' +
+          '    in App (at **)',
+      ]);
 
       assertLog([1]);
       expect(root).toMatchRenderedOutput('1');
@@ -322,12 +373,36 @@ describe('act warnings', () => {
       expect(root).toMatchRenderedOutput('Loading...');
 
       // This is a retry, not a ping, because we already showed a fallback.
-      expect(() => resolveText('Async')).toErrorDev(
+      resolveText('Async');
+      assertConsoleErrorDev(
         [
-          'A suspended resource finished loading inside a test, but the event ' +
-            'was not wrapped in act(...)',
-
-          ...(gate('enableSiblingPrerendering') ? ['not wrapped in act'] : []),
+          'A suspended resource finished loading inside a test, but the event was not wrapped in act(...).\n' +
+            '\n' +
+            'When testing, code that resolves suspended data should be wrapped into act(...):\n' +
+            '\n' +
+            'act(() => {\n' +
+            '  /* finish loading suspended data */\n' +
+            '});\n' +
+            '/* assert on the output */\n' +
+            '\n' +
+            "This ensures that you're testing the behavior the user would see in the browser. " +
+            'Learn more at https://react.dev/link/wrap-tests-with-act',
+
+          ...(gate('enableSiblingPrerendering')
+            ? [
+                'A suspended resource finished loading inside a test, but the event was not wrapped in act(...).\n' +
+                  '\n' +
+                  'When testing, code that resolves suspended data should be wrapped into act(...):\n' +
+                  '\n' +
+                  'act(() => {\n' +
+                  '  /* finish loading suspended data */\n' +
+                  '});\n' +
+                  '/* assert on the output */\n' +
+                  '\n' +
+                  "This ensures that you're testing the behavior the user would see in the browser. " +
+                  'Learn more at https://react.dev/link/wrap-tests-with-act',
+              ]
+            : []),
         ],
 
         {withoutStack: true},
@@ -363,9 +438,21 @@ describe('act warnings', () => {
       expect(root).toMatchRenderedOutput('(empty)');
 
       // This is a ping, not a retry, because no fallback is showing.
-      expect(() => resolveText('Async')).toErrorDev(
-        'A suspended resource finished loading inside a test, but the event ' +
-          'was not wrapped in act(...)',
+      resolveText('Async');
+      assertConsoleErrorDev(
+        [
+          'A suspended resource finished loading inside a test, but the event was not wrapped in act(...).\n' +
+            '\n' +
+            'When testing, code that resolves suspended data should be wrapped into act(...):\n' +
+            '\n' +
+            'act(() => {\n' +
+            '  /* finish loading suspended data */\n' +
+            '});\n' +
+            '/* assert on the output */\n' +
+            '\n' +
+            "This ensures that you're testing the behavior the user would see in the browser. " +
+            'Learn more at https://react.dev/link/wrap-tests-with-act',
+        ],
         {withoutStack: true},
       );
     });
diff --git a/packages/react-reconciler/src/__tests__/ReactAsyncActions-test.js b/packages/react-reconciler/src/__tests__/ReactAsyncActions-test.js
index 843d5b2dd3fe6..43e071d4141cf 100644
--- a/packages/react-reconciler/src/__tests__/ReactAsyncActions-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactAsyncActions-test.js
@@ -7,6 +7,7 @@ let useTransition;
 let useState;
 let useOptimistic;
 let textCache;
+let assertConsoleErrorDev;
 
 describe('ReactAsyncActions', () => {
   beforeEach(() => {
@@ -21,6 +22,8 @@ describe('ReactAsyncActions', () => {
     Scheduler = require('scheduler');
     act = require('internal-test-utils').act;
     assertLog = require('internal-test-utils').assertLog;
+    assertConsoleErrorDev =
+      require('internal-test-utils').assertConsoleErrorDev;
     useTransition = React.useTransition;
     useState = React.useState;
     useOptimistic = React.useOptimistic;
@@ -1231,15 +1234,16 @@ describe('ReactAsyncActions', () => {
     assertLog(['A']);
     expect(root).toMatchRenderedOutput(A
);
 
-    await expect(async () => {
-      await act(() => {
-        setLoadingProgress('25%');
-        startTransition(() => setText('B'));
-      });
-    }).toErrorDev(
-      'An optimistic state update occurred outside a transition or ' +
-        'action. To fix, move the update to an action, or wrap ' +
-        'with startTransition.',
+    await act(() => {
+      setLoadingProgress('25%');
+      startTransition(() => setText('B'));
+    });
+    assertConsoleErrorDev(
+      [
+        'An optimistic state update occurred outside a transition or ' +
+          'action. To fix, move the update to an action, or wrap ' +
+          'with startTransition.',
+      ],
       {withoutStack: true},
     );
     assertLog(['Loading... (25%)', 'A', 'B']);
diff --git a/packages/react-reconciler/src/__tests__/ReactFragment-test.js b/packages/react-reconciler/src/__tests__/ReactFragment-test.js
index fe1d1f4f953db..559ede0dd9103 100644
--- a/packages/react-reconciler/src/__tests__/ReactFragment-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactFragment-test.js
@@ -12,6 +12,7 @@
 let React;
 let ReactNoop;
 let waitForAll;
+let assertConsoleErrorDev;
 
 describe('ReactFragment', () => {
   beforeEach(function () {
@@ -22,6 +23,7 @@ describe('ReactFragment', () => {
 
     const InternalTestUtils = require('internal-test-utils');
     waitForAll = InternalTestUtils.waitForAll;
+    assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
   });
 
   it('should render a single child via noop renderer', async () => {
@@ -740,9 +742,22 @@ describe('ReactFragment', () => {
     await waitForAll([]);
 
     ReactNoop.render();
-    await expect(async () => await waitForAll([])).toErrorDev(
-      'Each child in a list should have a unique "key" prop.',
-    );
+    await waitForAll([]);
+    assertConsoleErrorDev([
+      gate('enableOwnerStacks')
+        ? 'Each child in a list should have a unique "key" prop.\n' +
+          '\n' +
+          'Check the render method of `div`. ' +
+          'It was passed a child from Foo. ' +
+          'See https://react.dev/link/warning-keys for more information.\n' +
+          '    in Foo (at **)'
+        : 'Each child in a list should have a unique "key" prop.\n' +
+          '\n' +
+          'Check the render method of `Foo`. ' +
+          'See https://react.dev/link/warning-keys for more information.\n' +
+          '    in Stateful (at **)\n' +
+          '    in Foo (at **)',
+    ]);
 
     expect(ops).toEqual([]);
     expect(ReactNoop).toMatchRenderedOutput(
@@ -937,9 +952,16 @@ describe('ReactFragment', () => {
     }
 
     ReactNoop.render();
-    await expect(async () => await waitForAll([])).toErrorDev(
-      'Each child in a list should have a unique "key" prop.',
-    );
+    await waitForAll([]);
+    assertConsoleErrorDev([
+      'Each child in a list should have a unique "key" prop.\n' +
+        '\n' +
+        'Check the top-level render call using . ' +
+        'It was passed a child from Foo. ' +
+        'See https://react.dev/link/warning-keys for more information.\n' +
+        '    in span (at **)\n' +
+        '    in Foo (at **)',
+    ]);
 
     ReactNoop.render();
     // The key warning gets deduped because it's in the same component.
diff --git a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
index 8b0e903a839e9..367d83f38a57c 100644
--- a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
@@ -239,17 +239,18 @@ describe('ReactHooks', () => {
     await waitForAll(['Count: 0']);
     expect(root).toMatchRenderedOutput('0');
 
-    await expect(async () => {
-      await act(() =>
-        setCounter(1, () => {
-          throw new Error('Expected to ignore the callback.');
-        }),
-      );
-    }).toErrorDev(
-      'State updates from the useState() and useReducer() Hooks ' +
-        "don't support the second callback argument. " +
-        'To execute a side effect after rendering, ' +
-        'declare it in the component body with useEffect().',
+    await act(() =>
+      setCounter(1, () => {
+        throw new Error('Expected to ignore the callback.');
+      }),
+    );
+    assertConsoleErrorDev(
+      [
+        'State updates from the useState() and useReducer() Hooks ' +
+          "don't support the second callback argument. " +
+          'To execute a side effect after rendering, ' +
+          'declare it in the component body with useEffect().',
+      ],
       {withoutStack: true},
     );
     assertLog(['Count: 1']);
@@ -273,17 +274,18 @@ describe('ReactHooks', () => {
     await waitForAll(['Count: 0']);
     expect(root).toMatchRenderedOutput('0');
 
-    await expect(async () => {
-      await act(() =>
-        dispatch(1, () => {
-          throw new Error('Expected to ignore the callback.');
-        }),
-      );
-    }).toErrorDev(
-      'State updates from the useState() and useReducer() Hooks ' +
-        "don't support the second callback argument. " +
-        'To execute a side effect after rendering, ' +
-        'declare it in the component body with useEffect().',
+    await act(() =>
+      dispatch(1, () => {
+        throw new Error('Expected to ignore the callback.');
+      }),
+    );
+    assertConsoleErrorDev(
+      [
+        'State updates from the useState() and useReducer() Hooks ' +
+          "don't support the second callback argument. " +
+          'To execute a side effect after rendering, ' +
+          'declare it in the component body with useEffect().',
+      ],
       {withoutStack: true},
     );
     assertLog(['Count: 1']);
@@ -581,16 +583,17 @@ describe('ReactHooks', () => {
       });
     });
     assertLog(['Did commit: A']);
-    await expect(async () => {
-      await act(() => {
-        root.update();
-      });
-    }).toErrorDev([
+    await act(() => {
+      root.update();
+    });
+    assertConsoleErrorDev([
       'The final argument passed to useLayoutEffect changed size ' +
         'between renders. The order and size of this array must remain ' +
-        'constant.\n\n' +
+        'constant.\n' +
+        '\n' +
         'Previous: [A]\n' +
-        'Incoming: [A, B]\n',
+        'Incoming: [A, B]\n' +
+        '    in App (at **)',
     ]);
   });
 
@@ -617,14 +620,14 @@ describe('ReactHooks', () => {
     assertLog(['Compute']);
     expect(root).toMatchRenderedOutput('HELLO');
 
-    await expect(async () => {
-      await act(() => {
-        root.update();
-      });
-    }).toErrorDev([
+    await act(() => {
+      root.update();
+    });
+    assertConsoleErrorDev([
       'useMemo received a final argument during this render, but ' +
         'not during the previous render. Even though the final argument is ' +
-        'optional, its type cannot change between renders.',
+        'optional, its type cannot change between renders.\n' +
+        '    in App (at **)',
     ]);
   });
 
@@ -639,53 +642,62 @@ describe('ReactHooks', () => {
       return null;
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(, {
-          unstable_isConcurrent: true,
-        });
+    await act(() => {
+      ReactTestRenderer.create(, {
+        unstable_isConcurrent: true,
       });
-    }).toErrorDev([
+    });
+    assertConsoleErrorDev([
       'useEffect received a final argument that is not an array (instead, received `string`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
       'useLayoutEffect received a final argument that is not an array (instead, received `string`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
       'useMemo received a final argument that is not an array (instead, received `string`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
       'useCallback received a final argument that is not an array (instead, received `string`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
     ]);
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(, {
-          unstable_isConcurrent: true,
-        });
+    await act(() => {
+      ReactTestRenderer.create(, {
+        unstable_isConcurrent: true,
       });
-    }).toErrorDev([
+    });
+    assertConsoleErrorDev([
       'useEffect received a final argument that is not an array (instead, received `number`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
       'useLayoutEffect received a final argument that is not an array (instead, received `number`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
       'useMemo received a final argument that is not an array (instead, received `number`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
       'useCallback received a final argument that is not an array (instead, received `number`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
     ]);
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(, {
-          unstable_isConcurrent: true,
-        });
+    await act(() => {
+      ReactTestRenderer.create(, {
+        unstable_isConcurrent: true,
       });
-    }).toErrorDev([
+    });
+    assertConsoleErrorDev([
       'useEffect received a final argument that is not an array (instead, received `object`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
       'useLayoutEffect received a final argument that is not an array (instead, received `object`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
       'useMemo received a final argument that is not an array (instead, received `object`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
       'useCallback received a final argument that is not an array (instead, received `object`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
     ]);
 
     await act(() => {
@@ -710,15 +722,15 @@ describe('ReactHooks', () => {
     });
     App.displayName = 'App';
 
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(, {
-          unstable_isConcurrent: true,
-        });
+    await act(() => {
+      ReactTestRenderer.create(, {
+        unstable_isConcurrent: true,
       });
-    }).toErrorDev([
+    });
+    assertConsoleErrorDev([
       'useImperativeHandle received a final argument that is not an array (instead, received `string`). ' +
-        'When specified, the final argument must be an array.',
+        'When specified, the final argument must be an array.\n' +
+        '    in App (at **)',
     ]);
     await act(() => {
       ReactTestRenderer.create(, {
@@ -817,17 +829,18 @@ describe('ReactHooks', () => {
     }
 
     await expect(async () => {
-      await expect(async () => {
-        await act(() => {
-          ReactTestRenderer.create(, {unstable_isConcurrent: true});
-        });
-      }).rejects.toThrow('create is not a function');
-    }).toErrorDev([
+      await act(() => {
+        ReactTestRenderer.create(, {unstable_isConcurrent: true});
+      });
+    }).rejects.toThrow('create is not a function');
+    assertConsoleErrorDev([
+      'Expected useImperativeHandle() second argument to be a function ' +
+        'that creates a handle. Instead received: undefined.\n' +
+        '    in App (at **)',
       'Expected useImperativeHandle() first argument to either be a ' +
         'ref callback or React.createRef() object. ' +
-        'Instead received: an object with keys {focus}.',
-      'Expected useImperativeHandle() second argument to be a function ' +
-        'that creates a handle. Instead received: undefined.',
+        'Instead received: an object with keys {focus}.\n' +
+        '    in App (at **)',
     ]);
   });
 
@@ -841,13 +854,13 @@ describe('ReactHooks', () => {
     });
     App.displayName = 'App';
 
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(, {unstable_isConcurrent: true});
-      });
-    }).toErrorDev([
+    await act(() => {
+      ReactTestRenderer.create(, {unstable_isConcurrent: true});
+    });
+    assertConsoleErrorDev([
       'Expected useImperativeHandle() second argument to be a function ' +
-        'that creates a handle. Instead received: object.',
+        'that creates a handle. Instead received: object.\n' +
+        '    in App (at **)',
     ]);
   });
 
@@ -933,13 +946,15 @@ describe('ReactHooks', () => {
       });
       return null;
     }
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(, {unstable_isConcurrent: true});
-      });
-    }).toErrorDev(
-      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks.',
-    );
+    await act(() => {
+      ReactTestRenderer.create(, {unstable_isConcurrent: true});
+    });
+    assertConsoleErrorDev([
+      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
+        'You can only call Hooks at the top level of your React function. ' +
+        'For more information, see https://react.dev/link/rules-of-hooks\n' +
+        '    in App (at **)',
+    ]);
   });
 
   it('warns when reading context inside useMemo', async () => {
@@ -954,11 +969,16 @@ describe('ReactHooks', () => {
       }, []);
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(, {unstable_isConcurrent: true});
-      });
-    }).toErrorDev('Context can only be read while React is rendering');
+    await act(() => {
+      ReactTestRenderer.create(, {unstable_isConcurrent: true});
+    });
+    assertConsoleErrorDev([
+      'Context can only be read while React is rendering. ' +
+        'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
+        'In function components, you can read it directly in the function body, ' +
+        'but not inside Hooks like useReducer() or useMemo().\n' +
+        '    in App (at **)',
+    ]);
   });
 
   it('warns when reading context inside useMemo after reading outside it', async () => {
@@ -977,11 +997,16 @@ describe('ReactHooks', () => {
       }, []);
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(, {unstable_isConcurrent: true});
-      });
-    }).toErrorDev('Context can only be read while React is rendering');
+    await act(() => {
+      ReactTestRenderer.create(, {unstable_isConcurrent: true});
+    });
+    assertConsoleErrorDev([
+      'Context can only be read while React is rendering. ' +
+        'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
+        'In function components, you can read it directly in the function body, ' +
+        'but not inside Hooks like useReducer() or useMemo().\n' +
+        '    in App (at **)',
+    ]);
     expect(firstRead).toBe('light');
     expect(secondRead).toBe('light');
   });
@@ -1048,11 +1073,16 @@ describe('ReactHooks', () => {
       return null;
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(, {unstable_isConcurrent: true});
-      });
-    }).toErrorDev(['Context can only be read while React is rendering']);
+    await act(() => {
+      ReactTestRenderer.create(, {unstable_isConcurrent: true});
+    });
+    assertConsoleErrorDev([
+      'Context can only be read while React is rendering. ' +
+        'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
+        'In function components, you can read it directly in the function body, ' +
+        'but not inside Hooks like useReducer() or useMemo().\n' +
+        '    in App (at **)',
+    ]);
   });
 
   // Edge case.
@@ -1078,19 +1108,25 @@ describe('ReactHooks', () => {
       }
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(
-          <>
-            
-            
-          >,
-          {unstable_isConcurrent: true},
-        );
-      });
-    }).toErrorDev([
-      'Context can only be read while React is rendering',
-      'Cannot update a component (`Fn`) while rendering a different component (`Cls`).',
+    await act(() => {
+      ReactTestRenderer.create(
+        <>
+          
+          
+        >,
+        {unstable_isConcurrent: true},
+      );
+    });
+    assertConsoleErrorDev([
+      'Context can only be read while React is rendering. ' +
+        'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
+        'In function components, you can read it directly in the function body, ' +
+        'but not inside Hooks like useReducer() or useMemo().\n' +
+        '    in Cls (at **)',
+      'Cannot update a component (`Fn`) while rendering a different component (`Cls`). ' +
+        'To locate the bad setState() call inside `Cls`, ' +
+        'follow the stack trace as described in https://react.dev/link/setstate-in-render\n' +
+        '    in Cls (at **)',
     ]);
   });
 
@@ -1110,24 +1146,32 @@ describe('ReactHooks', () => {
     }
 
     await expect(async () => {
-      await expect(async () => {
-        await act(() => {
-          ReactTestRenderer.create(, {unstable_isConcurrent: true});
-        });
-      }).rejects.toThrow(
-        'Update hook called on initial render. This is likely a bug in React. Please file an issue.',
-      );
-    }).toErrorDev([
-      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks',
+      await act(() => {
+        ReactTestRenderer.create(, {unstable_isConcurrent: true});
+      });
+    }).rejects.toThrow(
+      'Update hook called on initial render. This is likely a bug in React. Please file an issue.',
+    );
+    assertConsoleErrorDev([
+      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
+        'You can only call Hooks at the top level of your React function. ' +
+        'For more information, see https://react.dev/link/rules-of-hooks\n' +
+        '    in App (at **)',
       'React has detected a change in the order of Hooks called by App. ' +
         'This will lead to bugs and errors if not fixed. For more information, ' +
-        'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n\n' +
+        'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n' +
+        '\n' +
         '   Previous render            Next render\n' +
         '   ------------------------------------------------------\n' +
         '1. useReducer                 useReducer\n' +
         '2. useState                   useRef\n' +
-        '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n',
-      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks',
+        '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' +
+        '\n' +
+        '    in App (at **)',
+      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
+        'You can only call Hooks at the top level of your React function. ' +
+        'For more information, see https://react.dev/link/rules-of-hooks\n' +
+        '    in App (at **)',
     ]);
   });
 
@@ -1140,13 +1184,15 @@ describe('ReactHooks', () => {
       });
       return null;
     }
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(, {unstable_isConcurrent: true});
-      });
-    }).toErrorDev(
-      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks.',
-    );
+    await act(() => {
+      ReactTestRenderer.create(, {unstable_isConcurrent: true});
+    });
+    assertConsoleErrorDev([
+      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
+        'You can only call Hooks at the top level of your React function. ' +
+        'For more information, see https://react.dev/link/rules-of-hooks\n' +
+        '    in App (at **)',
+    ]);
   });
 
   it('resets warning internal state when interrupted by an error', async () => {
@@ -1177,21 +1223,37 @@ describe('ReactHooks', () => {
       }
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(
-          
-            
-          ,
-          {unstable_isConcurrent: true},
-        );
-      });
-    }).toErrorDev([
-      'Context can only be read while React is rendering',
-      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks',
-
-      'Context can only be read while React is rendering',
-      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks',
+    await act(() => {
+      ReactTestRenderer.create(
+        
+          
+        ,
+        {unstable_isConcurrent: true},
+      );
+    });
+    assertConsoleErrorDev([
+      'Context can only be read while React is rendering. ' +
+        'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
+        'In function components, you can read it directly in the function body, ' +
+        'but not inside Hooks like useReducer() or useMemo().\n' +
+        '    in App (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in Boundary (at **)'),
+      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
+        'You can only call Hooks at the top level of your React function. ' +
+        'For more information, see https://react.dev/link/rules-of-hooks\n' +
+        '    in App (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in Boundary (at **)'),
+      'Context can only be read while React is rendering. ' +
+        'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
+        'In function components, you can read it directly in the function body, ' +
+        'but not inside Hooks like useReducer() or useMemo().\n' +
+        '    in App (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in Boundary (at **)'),
+      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
+        'You can only call Hooks at the top level of your React function. ' +
+        'For more information, see https://react.dev/link/rules-of-hooks\n' +
+        '    in App (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in Boundary (at **)'),
     ]);
 
     function Valid() {
@@ -1218,21 +1280,37 @@ describe('ReactHooks', () => {
     });
 
     // Verify warnings don't get permanently disabled.
-    await expect(async () => {
-      await act(() => {
-        ReactTestRenderer.create(
-          
-            
-          ,
-          {unstable_isConcurrent: true},
-        );
-      });
-    }).toErrorDev([
-      'Context can only be read while React is rendering',
-      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks',
-
-      'Context can only be read while React is rendering',
-      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks',
+    await act(() => {
+      ReactTestRenderer.create(
+        
+          
+        ,
+        {unstable_isConcurrent: true},
+      );
+    });
+    assertConsoleErrorDev([
+      'Context can only be read while React is rendering. ' +
+        'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
+        'In function components, you can read it directly in the function body, ' +
+        'but not inside Hooks like useReducer() or useMemo().\n' +
+        '    in App (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in Boundary (at **)'),
+      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
+        'You can only call Hooks at the top level of your React function. ' +
+        'For more information, see https://react.dev/link/rules-of-hooks\n' +
+        '    in App (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in Boundary (at **)'),
+      'Context can only be read while React is rendering. ' +
+        'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
+        'In function components, you can read it directly in the function body, ' +
+        'but not inside Hooks like useReducer() or useMemo().\n' +
+        '    in App (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in Boundary (at **)'),
+      'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
+        'You can only call Hooks at the top level of your React function. ' +
+        'For more information, see https://react.dev/link/rules-of-hooks\n' +
+        '    in App (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in Boundary (at **)'),
     ]);
   });
 
@@ -1569,24 +1647,26 @@ describe('ReactHooks', () => {
             unstable_isConcurrent: true,
           });
         });
-        await expect(async () => {
-          try {
-            await act(() => {
-              root.update();
-            });
-          } catch (error) {
-            // Swapping certain types of hooks will cause runtime errors.
-            // This is okay as far as this test is concerned.
-            // We just want to verify that warnings are always logged.
-          }
-        }).toErrorDev([
+        try {
+          await act(() => {
+            root.update();
+          });
+        } catch (error) {
+          // Swapping certain types of hooks will cause runtime errors.
+          // This is okay as far as this test is concerned.
+          // We just want to verify that warnings are always logged.
+        }
+        assertConsoleErrorDev([
           'React has detected a change in the order of Hooks called by App. ' +
             'This will lead to bugs and errors if not fixed. For more information, ' +
-            'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n\n' +
+            'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n' +
+            '\n' +
             '   Previous render            Next render\n' +
             '   ------------------------------------------------------\n' +
             `1. ${formatHookNamesToMatchErrorMessage(hookNameA, hookNameB)}\n` +
-            '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n',
+            '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' +
+            '\n' +
+            '    in App (at **)',
         ]);
 
         // further warnings for this component are silenced
@@ -1618,25 +1698,27 @@ describe('ReactHooks', () => {
           });
         });
 
-        await expect(async () => {
-          try {
-            await act(() => {
-              root.update();
-            });
-          } catch (error) {
-            // Swapping certain types of hooks will cause runtime errors.
-            // This is okay as far as this test is concerned.
-            // We just want to verify that warnings are always logged.
-          }
-        }).toErrorDev([
+        try {
+          await act(() => {
+            root.update();
+          });
+        } catch (error) {
+          // Swapping certain types of hooks will cause runtime errors.
+          // This is okay as far as this test is concerned.
+          // We just want to verify that warnings are always logged.
+        }
+        assertConsoleErrorDev([
           'React has detected a change in the order of Hooks called by App. ' +
             'This will lead to bugs and errors if not fixed. For more information, ' +
-            'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n\n' +
+            'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n' +
+            '\n' +
             '   Previous render            Next render\n' +
             '   ------------------------------------------------------\n' +
             `1. ${formatHookNamesToMatchErrorMessage(hookNameA, hookNameA)}\n` +
             `2. undefined                  use${hookNameB}\n` +
-            '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n',
+            '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' +
+            '\n' +
+            '    in App (at **)',
         ]);
       });
     });
@@ -1701,24 +1783,26 @@ describe('ReactHooks', () => {
             unstable_isConcurrent: true,
           });
         });
-        await expect(async () => {
-          await act(() => {
-            root.update();
-          }).catch(e => {});
-          // Swapping certain types of hooks will cause runtime errors.
-          // This is okay as far as this test is concerned.
-          // We just want to verify that warnings are always logged.
-        }).toErrorDev([
+        await act(() => {
+          root.update();
+        }).catch(e => {});
+        // Swapping certain types of hooks will cause runtime errors.
+        // This is okay as far as this test is concerned.
+        // We just want to verify that warnings are always logged.
+        assertConsoleErrorDev([
           'React has detected a change in the order of Hooks called by App. ' +
             'This will lead to bugs and errors if not fixed. For more information, ' +
-            'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n\n' +
+            'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n' +
+            '\n' +
             '   Previous render            Next render\n' +
             '   ------------------------------------------------------\n' +
             `1. ${formatHookNamesToMatchErrorMessage(
               'ImperativeHandle',
               'Memo',
             )}\n` +
-            '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n',
+            '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' +
+            '\n' +
+            '    in App (at **)',
         ]);
 
         // further warnings for this component are silenced
@@ -1751,19 +1835,21 @@ describe('ReactHooks', () => {
         });
       });
       await expect(async () => {
-        await expect(async () => {
-          await act(() => {
-            root.update();
-          });
-        }).rejects.toThrow('custom error');
-      }).toErrorDev([
+        await act(() => {
+          root.update();
+        });
+      }).rejects.toThrow('custom error');
+      assertConsoleErrorDev([
         'React has detected a change in the order of Hooks called by App. ' +
           'This will lead to bugs and errors if not fixed. For more information, ' +
-          'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n\n' +
+          'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n' +
+          '\n' +
           '   Previous render            Next render\n' +
           '   ------------------------------------------------------\n' +
           '1. useReducer                 useState\n' +
-          '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n',
+          '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' +
+          '\n' +
+          '    in App (at **)',
       ]);
     });
   });
@@ -1798,8 +1884,10 @@ describe('ReactHooks', () => {
       });
     }).rejects.toThrow('Hello');
     assertConsoleErrorDev([
-      'Cannot update a component (`A`) while rendering ' +
-        'a different component (`B`).',
+      'Cannot update a component (`A`) while rendering a different component (`B`). ' +
+        'To locate the bad setState() call inside `B`, ' +
+        'follow the stack trace as described in https://react.dev/link/setstate-in-render\n' +
+        '    in B (at **)',
     ]);
   });
 
diff --git a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js
index dcb362669928e..e4febdb3e28f1 100644
--- a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js
@@ -42,6 +42,7 @@ let waitForThrow;
 let waitForPaint;
 let assertLog;
 let useResourceEffect;
+let assertConsoleErrorDev;
 
 describe('ReactHooksWithNoopRenderer', () => {
   beforeEach(() => {
@@ -52,6 +53,8 @@ describe('ReactHooksWithNoopRenderer', () => {
     ReactNoop = require('react-noop-renderer');
     Scheduler = require('scheduler');
     act = require('internal-test-utils').act;
+    assertConsoleErrorDev =
+      require('internal-test-utils').assertConsoleErrorDev;
     useState = React.useState;
     useReducer = React.useReducer;
     useEffect = React.useEffect;
@@ -232,17 +235,18 @@ describe('ReactHooksWithNoopRenderer', () => {
   });
 
   it('throws when called outside the render phase', async () => {
-    expect(() => {
-      expect(() => useState(0)).toThrow(
-        "Cannot read property 'useState' of null",
-      );
-    }).toErrorDev(
-      'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
-        ' one of the following reasons:\n' +
-        '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
-        '2. You might be breaking the Rules of Hooks\n' +
-        '3. You might have more than one copy of React in the same app\n' +
-        'See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.',
+    expect(() => useState(0)).toThrow(
+      "Cannot read property 'useState' of null",
+    );
+    assertConsoleErrorDev(
+      [
+        'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
+          ' one of the following reasons:\n' +
+          '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
+          '2. You might be breaking the Rules of Hooks\n' +
+          '3. You might have more than one copy of React in the same app\n' +
+          'See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.',
+      ],
       {withoutStack: true},
     );
   });
@@ -459,11 +463,12 @@ describe('ReactHooksWithNoopRenderer', () => {
           
         >,
       );
-      await expect(
-        async () => await waitForAll(['Foo [0]', 'Bar', 'Foo [1]']),
-      ).toErrorDev([
-        'Cannot update a component (`Foo`) while rendering a ' +
-          'different component (`Bar`). To locate the bad setState() call inside `Bar`',
+      await waitForAll(['Foo [0]', 'Bar', 'Foo [1]']);
+      assertConsoleErrorDev([
+        'Cannot update a component (`Foo`) while rendering a different component (`Bar`). ' +
+          'To locate the bad setState() call inside `Bar`, ' +
+          'follow the stack trace as described in https://react.dev/link/setstate-in-render\n' +
+          '    in Bar (at **)',
       ]);
 
       // It should not warn again (deduplication).
@@ -1645,6 +1650,12 @@ describe('ReactHooksWithNoopRenderer', () => {
             updateCount(props.count);
           });
           assertLog([`Schedule update [${props.count}]`]);
+          assertConsoleErrorDev([
+            'flushSync was called from inside a lifecycle method. ' +
+              'React cannot flush when React is already rendering. ' +
+              'Consider moving this call to a scheduler task or micro task.\n' +
+              '    in Counter (at **)',
+          ]);
           // This shouldn't flush synchronously.
           expect(ReactNoop).not.toMatchRenderedOutput(
             ,
@@ -1652,17 +1663,14 @@ describe('ReactHooksWithNoopRenderer', () => {
         }, [props.count]);
         return ;
       }
-      await expect(async () => {
-        await act(async () => {
-          ReactNoop.render(, () =>
-            Scheduler.log('Sync effect'),
-          );
-          await waitFor(['Count: (empty)', 'Sync effect']);
-          expect(ReactNoop).toMatchRenderedOutput(
-            ,
-          );
-        });
-      }).toErrorDev('flushSync was called from inside a lifecycle method');
+      await act(async () => {
+        ReactNoop.render(, () =>
+          Scheduler.log('Sync effect'),
+        );
+        await waitFor(['Count: (empty)', 'Sync effect']);
+        expect(ReactNoop).toMatchRenderedOutput();
+      });
+
       assertLog([`Count: 0`]);
       expect(ReactNoop).toMatchRenderedOutput();
     });
@@ -2506,35 +2514,47 @@ describe('ReactHooksWithNoopRenderer', () => {
       }
 
       const root1 = ReactNoop.createRoot();
-      await expect(async () => {
-        await act(() => {
-          root1.render();
-        });
-      }).toErrorDev([
-        'useEffect must not return anything besides a ' +
-          'function, which is used for clean-up. You returned: 17',
+      await act(() => {
+        root1.render();
+      });
+      assertConsoleErrorDev([
+        'useEffect must not return anything besides a function, ' +
+          'which is used for clean-up. You returned: 17\n' +
+          '    in App (at **)',
       ]);
 
       const root2 = ReactNoop.createRoot();
-      await expect(async () => {
-        await act(() => {
-          root2.render();
-        });
-      }).toErrorDev([
-        'useEffect must not return anything besides a ' +
-          'function, which is used for clean-up. You returned null. If your ' +
-          'effect does not require clean up, return undefined (or nothing).',
+      await act(() => {
+        root2.render();
+      });
+      assertConsoleErrorDev([
+        'useEffect must not return anything besides a function, ' +
+          'which is used for clean-up. You returned null. ' +
+          'If your effect does not require clean up, return undefined (or nothing).\n' +
+          '    in App (at **)',
       ]);
 
       const root3 = ReactNoop.createRoot();
-      await expect(async () => {
-        await act(() => {
-          root3.render();
-        });
-      }).toErrorDev([
-        'useEffect must not return anything besides a ' +
-          'function, which is used for clean-up.\n\n' +
-          'It looks like you wrote useEffect(async () => ...) or returned a Promise.',
+      await act(() => {
+        root3.render();
+      });
+      assertConsoleErrorDev([
+        'useEffect must not return anything besides a function, which is used for clean-up.\n' +
+          '\n' +
+          'It looks like you wrote useEffect(async () => ...) or returned a Promise. ' +
+          'Instead, write the async function inside your effect and call it immediately:\n' +
+          '\n' +
+          'useEffect(() => {\n' +
+          '  async function fetchData() {\n' +
+          '    // You can await here\n' +
+          '    const response = await MyAPI.getData(someId);\n' +
+          '    // ...\n' +
+          '  }\n' +
+          '  fetchData();\n' +
+          "}, [someId]); // Or [] if effect doesn't need props or state\n" +
+          '\n' +
+          'Learn more about data fetching with Hooks: https://react.dev/link/hooks-data-fetching\n' +
+          '    in App (at **)',
       ]);
 
       // Error on unmount because React assumes the value is a function
@@ -2895,35 +2915,48 @@ describe('ReactHooksWithNoopRenderer', () => {
       }
 
       const root1 = ReactNoop.createRoot();
-      await expect(async () => {
-        await act(() => {
-          root1.render();
-        });
-      }).toErrorDev([
-        'useInsertionEffect must not return anything besides a ' +
-          'function, which is used for clean-up. You returned: 17',
+      await act(() => {
+        root1.render();
+      });
+      assertConsoleErrorDev([
+        'useInsertionEffect must not return anything besides a function, ' +
+          'which is used for clean-up. You returned: 17\n' +
+          '    in App (at **)',
       ]);
 
       const root2 = ReactNoop.createRoot();
-      await expect(async () => {
-        await act(() => {
-          root2.render();
-        });
-      }).toErrorDev([
-        'useInsertionEffect must not return anything besides a ' +
-          'function, which is used for clean-up. You returned null. If your ' +
-          'effect does not require clean up, return undefined (or nothing).',
+      await act(() => {
+        root2.render();
+      });
+      assertConsoleErrorDev([
+        'useInsertionEffect must not return anything besides a function, ' +
+          'which is used for clean-up. You returned null. ' +
+          'If your effect does not require clean up, return undefined (or nothing).\n' +
+          '    in App (at **)',
       ]);
 
       const root3 = ReactNoop.createRoot();
-      await expect(async () => {
-        await act(() => {
-          root3.render();
-        });
-      }).toErrorDev([
+      await act(() => {
+        root3.render();
+      });
+      assertConsoleErrorDev([
         'useInsertionEffect must not return anything besides a ' +
-          'function, which is used for clean-up.\n\n' +
-          'It looks like you wrote useInsertionEffect(async () => ...) or returned a Promise.',
+          'function, which is used for clean-up.\n' +
+          '\n' +
+          'It looks like you wrote useInsertionEffect(async () => ...) or returned a Promise. ' +
+          'Instead, write the async function inside your effect and call it immediately:\n' +
+          '\n' +
+          'useInsertionEffect(() => {\n' +
+          '  async function fetchData() {\n' +
+          '    // You can await here\n' +
+          '    const response = await MyAPI.getData(someId);\n' +
+          '    // ...\n' +
+          '  }\n' +
+          '  fetchData();\n' +
+          "}, [someId]); // Or [] if effect doesn't need props or state\n" +
+          '\n' +
+          'Learn more about data fetching with Hooks: https://react.dev/link/hooks-data-fetching\n' +
+          '    in App (at **)',
       ]);
 
       // Error on unmount because React assumes the value is a function
@@ -2946,11 +2979,13 @@ describe('ReactHooksWithNoopRenderer', () => {
       }
 
       const root = ReactNoop.createRoot();
-      await expect(async () => {
-        await act(() => {
-          root.render();
-        });
-      }).toErrorDev(['useInsertionEffect must not schedule updates.']);
+      await act(() => {
+        root.render();
+      });
+      assertConsoleErrorDev([
+        'useInsertionEffect must not schedule updates.\n' +
+          '    in App (at **)',
+      ]);
 
       await act(async () => {
         root.render();
@@ -2988,11 +3023,13 @@ describe('ReactHooksWithNoopRenderer', () => {
       await act(() => {
         root.render();
       });
-      await expect(async () => {
-        await act(() => {
-          root.render();
-        });
-      }).toErrorDev(['useInsertionEffect must not schedule updates.']);
+      await act(() => {
+        root.render();
+      });
+      assertConsoleErrorDev([
+        'useInsertionEffect must not schedule updates.\n' +
+          '    in App (at **)',
+      ]);
 
       await act(async () => {
         root.render();
@@ -3036,19 +3073,17 @@ describe('ReactHooksWithNoopRenderer', () => {
         );
       });
 
-      if (gate(flags => flags.enableHiddenSubtreeInsertionEffectCleanup)) {
-        await expect(async () => {
-          await act(() => {
-            root.render();
-          });
-        }).toErrorDev(['useInsertionEffect must not schedule updates.']);
-      } else {
-        await expect(async () => {
-          await act(() => {
-            root.render();
-          });
-        }).toErrorDev([]);
-      }
+      await act(() => {
+        root.render();
+      });
+      assertConsoleErrorDev(
+        gate('enableHiddenSubtreeInsertionEffectCleanup')
+          ? [
+              'useInsertionEffect must not schedule updates.\n' +
+                '    in App (at **)',
+            ]
+          : [],
+      );
 
       // Should not warn for regular effects after throw.
       function NotInsertion() {
@@ -3225,35 +3260,47 @@ describe('ReactHooksWithNoopRenderer', () => {
       }
 
       const root1 = ReactNoop.createRoot();
-      await expect(async () => {
-        await act(() => {
-          root1.render();
-        });
-      }).toErrorDev([
+      await act(() => {
+        root1.render();
+      });
+      assertConsoleErrorDev([
         'useLayoutEffect must not return anything besides a ' +
-          'function, which is used for clean-up. You returned: 17',
+          'function, which is used for clean-up. You returned: 17\n' +
+          '    in App (at **)',
       ]);
 
       const root2 = ReactNoop.createRoot();
-      await expect(async () => {
-        await act(() => {
-          root2.render();
-        });
-      }).toErrorDev([
+      await act(() => {
+        root2.render();
+      });
+      assertConsoleErrorDev([
         'useLayoutEffect must not return anything besides a ' +
           'function, which is used for clean-up. You returned null. If your ' +
-          'effect does not require clean up, return undefined (or nothing).',
+          'effect does not require clean up, return undefined (or nothing).\n' +
+          '    in App (at **)',
       ]);
 
       const root3 = ReactNoop.createRoot();
-      await expect(async () => {
-        await act(() => {
-          root3.render();
-        });
-      }).toErrorDev([
+      await act(() => {
+        root3.render();
+      });
+      assertConsoleErrorDev([
         'useLayoutEffect must not return anything besides a ' +
           'function, which is used for clean-up.\n\n' +
-          'It looks like you wrote useLayoutEffect(async () => ...) or returned a Promise.',
+          'It looks like you wrote useLayoutEffect(async () => ...) or returned a Promise. ' +
+          'Instead, write the async function inside your effect and call it immediately:\n' +
+          '\n' +
+          'useLayoutEffect(() => {\n' +
+          '  async function fetchData() {\n' +
+          '    // You can await here\n' +
+          '    const response = await MyAPI.getData(someId);\n' +
+          '    // ...\n' +
+          '  }\n' +
+          '  fetchData();\n' +
+          "}, [someId]); // Or [] if effect doesn't need props or state\n" +
+          '\n' +
+          'Learn more about data fetching with Hooks: https://react.dev/link/hooks-data-fetching\n' +
+          '    in App (at **)',
       ]);
 
       // Error on unmount because React assumes the value is a function
@@ -3300,13 +3347,14 @@ describe('ReactHooksWithNoopRenderer', () => {
         return null;
       }
 
-      await expect(async () => {
-        await act(() => {
-          ReactNoop.render();
-        });
-      }).toErrorDev(
-        'useResourceEffect must provide a callback which returns a resource. ' +
-          'If a managed resource is not needed here, use useEffect. Received undefined',
+      await act(() => {
+        ReactNoop.render();
+      });
+      assertConsoleErrorDev(
+        [
+          'useResourceEffect must provide a callback which returns a resource. ' +
+            'If a managed resource is not needed here, use useEffect. Received undefined',
+        ],
         {withoutStack: true},
       );
     });
@@ -3328,14 +3376,14 @@ describe('ReactHooksWithNoopRenderer', () => {
         return null;
       }
 
-      await expect(async () => {
-        await act(() => {
-          ReactNoop.render();
-        });
-      }).toErrorDev(
+      await act(() => {
+        ReactNoop.render();
+      });
+      assertConsoleErrorDev([
         'useResourceEffect received a dependency array with no dependencies. ' +
-          'When specified, the dependency array must have at least one dependency.',
-      );
+          'When specified, the dependency array must have at least one dependency.\n' +
+          '    in App (at **)',
+      ]);
     });
 
     // @gate enableUseResourceEffectHook
@@ -4472,21 +4520,23 @@ describe('ReactHooksWithNoopRenderer', () => {
       );
 
       ReactNoop.render();
-      await expect(async () => {
-        await waitForThrow(
-          'Rendered more hooks than during the previous render.',
-        );
-        assertLog([]);
-      }).toErrorDev([
+      await waitForThrow(
+        'Rendered more hooks than during the previous render.',
+      );
+      assertLog([]);
+      assertConsoleErrorDev([
         'React has detected a change in the order of Hooks called by App. ' +
           'This will lead to bugs and errors if not fixed. For more information, ' +
-          'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n\n' +
+          'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n' +
+          '\n' +
           '   Previous render            Next render\n' +
           '   ------------------------------------------------------\n' +
           '1. useState                   useState\n' +
           '2. useState                   useState\n' +
           '3. undefined                  useState\n' +
-          '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n',
+          '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' +
+          '\n' +
+          '    in App (at **)',
       ]);
 
       // Uncomment if/when we support this again
@@ -4569,20 +4619,22 @@ describe('ReactHooksWithNoopRenderer', () => {
 
       await act(async () => {
         ReactNoop.render();
-        await expect(async () => {
-          await waitForThrow(
-            'Rendered more hooks than during the previous render.',
-          );
-          assertLog(['Unmount A']);
-        }).toErrorDev([
+        await waitForThrow(
+          'Rendered more hooks than during the previous render.',
+        );
+        assertLog(['Unmount A']);
+        assertConsoleErrorDev([
           'React has detected a change in the order of Hooks called by App. ' +
             'This will lead to bugs and errors if not fixed. For more information, ' +
-            'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n\n' +
+            'read the Rules of Hooks: https://react.dev/link/rules-of-hooks\n' +
+            '\n' +
             '   Previous render            Next render\n' +
             '   ------------------------------------------------------\n' +
             '1. useEffect                  useEffect\n' +
             '2. undefined                  useEffect\n' +
-            '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n',
+            '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' +
+            '\n' +
+            '    in App (at **)',
         ]);
       });
 
diff --git a/packages/react-reconciler/src/__tests__/ReactIncremental-test.js b/packages/react-reconciler/src/__tests__/ReactIncremental-test.js
index 50ed1ba5ee9b6..cf71014cce4fc 100644
--- a/packages/react-reconciler/src/__tests__/ReactIncremental-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactIncremental-test.js
@@ -1798,9 +1798,19 @@ describe('ReactIncremental', () => {
       'ShowBoth {"locale":"fr"}',
     ]);
     assertConsoleErrorDev([
-      'Intl uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'ShowLocale uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
-      'ShowBoth uses the legacy contextTypes API which will be removed soon. Use React.createContext() with React.useContext() instead.',
+      'Intl uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Intl (at **)',
+      'ShowLocale uses the legacy contextTypes API which will soon be removed. ' +
+        'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+        '    in ShowLocale (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in Intl (at **)'),
+      'ShowBoth uses the legacy contextTypes API which will be removed soon. ' +
+        'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in ShowBoth (at **)' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '\n    in div (at **)' + '\n    in Intl (at **)'),
     ]);
 
     ReactNoop.render(
@@ -1853,8 +1863,18 @@ describe('ReactIncremental', () => {
       'ShowBoth {"locale":"en"}',
     ]);
     assertConsoleErrorDev([
-      'Router uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'ShowRoute uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
+      'Router uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Router (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in Intl (at **)'),
+      'ShowRoute uses the legacy contextTypes API which will soon be removed. ' +
+        'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+        (gate('enableOwnerStacks')
+          ? '    in Indirection (at **)'
+          : '    in ShowRoute (at **)\n' +
+            '    in Indirection (at **)\n' +
+            '    in Router (at **)\n' +
+            '    in Intl (at **)'),
     ]);
   });
 
@@ -1890,8 +1910,12 @@ describe('ReactIncremental', () => {
       'Recurse {"n":0}',
     ]);
     assertConsoleErrorDev([
-      'Recurse uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'Recurse uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
+      'Recurse uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Recurse (at **)',
+      'Recurse uses the legacy contextTypes API which will soon be removed. ' +
+        'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Recurse (at **)',
     ]);
   });
 
@@ -1943,8 +1967,13 @@ describe('ReactIncremental', () => {
       'ShowLocale {"locale":"fr"}',
     ]);
     assertConsoleErrorDev([
-      'Intl uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'ShowLocale uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
+      'Intl uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Intl (at **)',
+      'ShowLocale uses the legacy contextTypes API which will soon be removed. ' +
+        'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+        '    in ShowLocale (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in Intl (at **)'),
     ]);
 
     await waitForAll([
@@ -2034,9 +2063,27 @@ describe('ReactIncremental', () => {
       'ShowLocaleFn:read {"locale":"fr"}',
     ]);
     assertConsoleErrorDev([
-      'Intl uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'ShowLocaleClass uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
-      'ShowLocaleFn uses the legacy contextTypes API which will be removed soon. Use React.createContext() with React.useContext() instead.',
+      'Intl uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Intl (at **)',
+      'ShowLocaleClass uses the legacy contextTypes API which will soon be removed. ' +
+        'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+        '    in ShowLocaleClass (at **)' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '\n    in Stateful (at **)' +
+            '\n    in IndirectionClass (at **)' +
+            '\n    in IndirectionFn (at **)' +
+            '    in Intl (at **)'),
+      'ShowLocaleFn uses the legacy contextTypes API which will be removed soon. ' +
+        'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in ShowLocaleFn (at **)' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '\n    in Stateful (at **)' +
+            '\n    in IndirectionClass (at **)' +
+            '\n    in IndirectionFn (at **)' +
+            '    in Intl (at **)'),
     ]);
 
     statefulInst.setState({x: 1});
@@ -2125,9 +2172,28 @@ describe('ReactIncremental', () => {
     ]);
 
     assertConsoleErrorDev([
-      'Intl uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'ShowLocaleClass uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
-      'ShowLocaleFn uses the legacy contextTypes API which will be removed soon. Use React.createContext() with React.useContext() instead.',
+      'Intl uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        (gate('enableOwnerStacks') ? '' : '    in Intl (at **)\n') +
+        '    in Stateful (at **)',
+      'ShowLocaleClass uses the legacy contextTypes API which will soon be removed. ' +
+        'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+        '    in ShowLocaleClass (at **)' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '\n    in IndirectionClass (at **)' +
+            '\n    in IndirectionFn (at **)' +
+            '\n    in Intl (at **)' +
+            '\n    in Stateful (at **)'),
+      'ShowLocaleFn uses the legacy contextTypes API which will be removed soon. ' +
+        'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in ShowLocaleFn (at **)' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '\n    in IndirectionClass (at **)' +
+            '\n    in IndirectionFn (at **)' +
+            '\n    in Intl (at **)' +
+            '\n    in Stateful (at **)'),
     ]);
 
     statefulInst.setState({locale: 'gr'});
@@ -2187,7 +2253,11 @@ describe('ReactIncremental', () => {
     await waitForAll([]);
 
     assertConsoleErrorDev([
-      'Child uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
+      'Child uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        (gate('enableOwnerStacks') ? '' : '    in Child (at **)\n') +
+        '    in Middle (at **)\n' +
+        '    in Root (at **)',
     ]);
 
     // Trigger an update in the middle of the tree
@@ -2235,8 +2305,12 @@ describe('ReactIncremental', () => {
 
     // Init
     ReactNoop.render();
-    await expect(async () => await waitForAll([])).toErrorDev([
-      'ContextProvider uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
+    await waitForAll([]);
+    assertConsoleErrorDev([
+      'ContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        (gate('enableOwnerStacks') ? '' : '    in ContextProvider (at **)\n') +
+        '    in Root (at **)',
     ]);
 
     // Trigger an update in the middle of the tree
@@ -2244,9 +2318,12 @@ describe('ReactIncremental', () => {
     instance.setState({
       throwError: true,
     });
-    await expect(async () => await waitForAll([])).toErrorDev(
-      'Error boundaries should implement getDerivedStateFromError()',
-    );
+    await waitForAll([]);
+    assertConsoleErrorDev([
+      'Root: Error boundaries should implement getDerivedStateFromError(). ' +
+        'In that method, return a state update to display an error message or fallback UI.\n' +
+        '    in Root (at **)',
+    ]);
   });
 
   // @gate !disableLegacyContext || !__DEV__
@@ -2292,7 +2369,9 @@ describe('ReactIncremental', () => {
     ]);
 
     assertConsoleErrorDev([
-      'MyComponent uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
+      'MyComponent uses the legacy contextTypes API which will soon be removed. ' +
+        'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+        '    in MyComponent (at **)',
     ]);
   });
 
@@ -2427,8 +2506,15 @@ describe('ReactIncremental', () => {
 
     await waitForAll(['count:0']);
     assertConsoleErrorDev([
-      'TopContextProvider uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
+      'TopContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in TopContextProvider (at **)',
+      'Child uses the legacy contextTypes API which will soon be removed. ' +
+        'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Child (at **)' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '\n    in Middle (at **)' + '\n    in TopContextProvider (at **)'),
     ]);
     instance.updateCount();
     await waitForAll(['count:1']);
@@ -2487,9 +2573,22 @@ describe('ReactIncremental', () => {
 
     await waitForAll(['count:0']);
     assertConsoleErrorDev([
-      'TopContextProvider uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'MiddleContextProvider uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
+      'TopContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in TopContextProvider (at **)',
+      'MiddleContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in MiddleContextProvider (at **)' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '\n    in TopContextProvider (at **)'),
+      'Child uses the legacy contextTypes API which will soon be removed. ' +
+        'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Child (at **)' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '\n    in MiddleContextProvider (at **)' +
+            '\n    in TopContextProvider (at **)'),
     ]);
     instance.updateCount();
     await waitForAll(['count:1']);
@@ -2557,9 +2656,24 @@ describe('ReactIncremental', () => {
 
     await waitForAll(['count:0']);
     assertConsoleErrorDev([
-      'TopContextProvider uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'MiddleContextProvider uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
+      'TopContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in TopContextProvider (at **)',
+      'MiddleContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in MiddleContextProvider (at **)' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '\n    in MiddleScu (at **)' +
+            '\n    in TopContextProvider (at **)'),
+      'Child uses the legacy contextTypes API which will soon be removed. ' +
+        'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Child (at **)' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '\n    in MiddleContextProvider (at **)' +
+            '\n    in MiddleScu (at **)' +
+            '\n    in TopContextProvider (at **)'),
     ]);
     instance.updateCount();
     await waitForAll([]);
@@ -2637,9 +2751,24 @@ describe('ReactIncremental', () => {
 
     await waitForAll(['count:0, name:brian']);
     assertConsoleErrorDev([
-      'TopContextProvider uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'MiddleContextProvider uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
+      'TopContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in TopContextProvider (at **)',
+      'MiddleContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in MiddleContextProvider (at **)' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '\n    in MiddleScu (at **)' +
+            '\n    in TopContextProvider (at **)'),
+      'Child uses the legacy contextTypes API which will soon be removed. ' +
+        'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Child (at **)' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '\n    in MiddleContextProvider (at **)' +
+            '\n    in MiddleScu (at **)' +
+            '\n    in TopContextProvider (at **)'),
     ]);
     topInstance.updateCount();
     await waitForAll([]);
@@ -2743,11 +2872,19 @@ describe('ReactIncremental', () => {
           
         ,
       );
-      await expect(async () => {
-        await waitForAll([]);
-      }).toErrorDev([
-        'Boundary uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
-        'Legacy context API has been detected within a strict-mode tree',
+      await waitForAll([]);
+      assertConsoleErrorDev([
+        'Boundary uses the legacy contextTypes API which will soon be removed. ' +
+          'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+          '    in Boundary (at **)',
+        'Legacy context API has been detected within a strict-mode tree.\n' +
+          '\n' +
+          'The old API will be supported in all 16.x releases, but applications using it should migrate to the new version.\n' +
+          '\n' +
+          'Please update the following components: Boundary\n' +
+          '\n' +
+          'Learn more about this warning here: https://react.dev/link/legacy-context\n' +
+          '    in Boundary (at **)',
       ]);
     }
 
diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js
index 2f0f23dca895b..028f80d3de41a 100644
--- a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js
@@ -1212,12 +1212,18 @@ describe('ReactIncrementalErrorHandling', () => {
       ,
     );
 
-    await expect(async () => {
-      await waitForAll([]);
-    }).toErrorDev([
-      'Provider uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
-      'Provider uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
-      'Connector uses the legacy contextTypes API which will be removed soon. Use React.createContext() with React.useContext() instead.',
+    await waitForAll([]);
+    assertConsoleErrorDev([
+      'Provider uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Provider (at **)',
+      'Provider uses the legacy contextTypes API which will soon be removed. ' +
+        'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Provider (at **)',
+      'Connector uses the legacy contextTypes API which will be removed soon. ' +
+        'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
+        '    in Connector (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in Provider (at **)'),
     ]);
 
     // If the context stack does not unwind, span will get 'abcde'
@@ -1250,9 +1256,19 @@ describe('ReactIncrementalErrorHandling', () => {
     await waitForAll([]);
     if (gate(flags => !flags.enableOwnerStacks)) {
       assertConsoleErrorDev([
-        'React.jsx: type is invalid -- expected a string',
+        'React.jsx: type is invalid -- expected a string (for built-in components) ' +
+          'or a class/function (for composite components) but got: undefined. ' +
+          "You likely forgot to export your component from the file it's defined in, " +
+          'or you might have mixed up default and named imports.\n' +
+          '    in BrokenRender (at **)\n' +
+          '    in ErrorBoundary (at **)',
         // React retries once on error
-        'React.jsx: type is invalid -- expected a string',
+        'React.jsx: type is invalid -- expected a string (for built-in components) ' +
+          'or a class/function (for composite components) but got: undefined. ' +
+          "You likely forgot to export your component from the file it's defined in, " +
+          'or you might have mixed up default and named imports.\n' +
+          '    in BrokenRender (at **)\n' +
+          '    in ErrorBoundary (at **)',
       ]);
     }
 
@@ -1305,9 +1321,19 @@ describe('ReactIncrementalErrorHandling', () => {
     await waitForAll([]);
     if (gate(flags => !flags.enableOwnerStacks)) {
       assertConsoleErrorDev([
-        'React.jsx: type is invalid -- expected a string',
+        'React.jsx: type is invalid -- expected a string (for built-in components) ' +
+          'or a class/function (for composite components) but got: undefined. ' +
+          "You likely forgot to export your component from the file it's defined in, " +
+          'or you might have mixed up default and named imports.\n' +
+          '    in BrokenRender (at **)\n' +
+          '    in ErrorBoundary (at **)',
         // React retries once on error
-        'React.jsx: type is invalid -- expected a string',
+        'React.jsx: type is invalid -- expected a string (for built-in components) ' +
+          'or a class/function (for composite components) but got: undefined. ' +
+          "You likely forgot to export your component from the file it's defined in, " +
+          'or you might have mixed up default and named imports.\n' +
+          '    in BrokenRender (at **)\n' +
+          '    in ErrorBoundary (at **)',
       ]);
     }
     expect(ReactNoop).toMatchRenderedOutput(
@@ -1330,7 +1356,12 @@ describe('ReactIncrementalErrorHandling', () => {
     ReactNoop.render();
     if (gate(flags => !flags.enableOwnerStacks)) {
       assertConsoleErrorDev(
-        ['React.jsx: type is invalid -- expected a string'],
+        [
+          'React.jsx: type is invalid -- expected a string (for built-in components) ' +
+            'or a class/function (for composite components) but got: undefined. ' +
+            "You likely forgot to export your component from the file it's defined in, " +
+            'or you might have mixed up default and named imports.',
+        ],
         {withoutStack: true},
       );
     }
diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorLogging-test.js b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorLogging-test.js
index 6aa4034636c31..75ca5f6b131dc 100644
--- a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorLogging-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorLogging-test.js
@@ -33,7 +33,7 @@ describe('ReactIncrementalErrorLogging', () => {
     waitForAll = InternalTestUtils.waitForAll;
   });
 
-  // Note: in this test file we won't be using toErrorDev() matchers
+  // Note: in this test file we won't be using assertConsoleDev() matchers
   // because they filter out precisely the messages we want to test for.
   let oldConsoleWarn;
   let oldConsoleError;
diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.js b/packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.js
index 4d4ab4f7c929e..b7a2d6b661f0a 100644
--- a/packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.js
@@ -18,6 +18,7 @@ let act;
 let waitForAll;
 let waitFor;
 let assertLog;
+let assertConsoleErrorDev;
 
 describe('ReactIncrementalUpdates', () => {
   beforeEach(() => {
@@ -34,6 +35,7 @@ describe('ReactIncrementalUpdates', () => {
     waitForAll = InternalTestUtils.waitForAll;
     waitFor = InternalTestUtils.waitFor;
     assertLog = InternalTestUtils.assertLog;
+    assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
   });
 
   function Text({text}) {
@@ -366,20 +368,21 @@ describe('ReactIncrementalUpdates', () => {
       return {a: 'a'};
     });
 
-    await expect(
-      async () =>
-        await waitForAll([
-          'setState updater',
-          // Updates in the render phase receive the currently rendering
-          // lane, so the update flushes immediately in the same render.
-          'render',
-        ]),
-    ).toErrorDev(
+    await waitForAll([
+      'setState updater',
+      // Updates in the render phase receive the currently rendering
+      // lane, so the update flushes immediately in the same render.
+      'render',
+    ]);
+    assertConsoleErrorDev([
       'An update (setState, replaceState, or forceUpdate) was scheduled ' +
         'from inside an update function. Update functions should be pure, ' +
         'with zero side-effects. Consider using componentDidUpdate or a ' +
-        'callback.\n\nPlease update the following component: Foo',
-    );
+        'callback.\n' +
+        '\n' +
+        'Please update the following component: Foo\n' +
+        '    in Foo (at **)',
+    ]);
     expect(instance.state).toEqual({a: 'a', b: 'b'});
 
     // Test deduplication (no additional warnings expected)
diff --git a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
index 1b665b2b8bc7f..748bfff6b0e7a 100644
--- a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
@@ -721,12 +721,13 @@ describe('ReactLazy', () => {
     }
     T.defaultProps = {inner: 'Hi'};
     const LazyText = lazy(() => fakeImport(T));
-    expect(() => {
-      LazyText.defaultProps = {outer: 'Bye'};
-    }).toErrorDev(
-      'It is not supported to assign `defaultProps` to ' +
-        'a lazy component import. Either specify them where the component ' +
-        'is defined, or create a wrapping component around it.',
+    LazyText.defaultProps = {outer: 'Bye'};
+    assertConsoleErrorDev(
+      [
+        'It is not supported to assign `defaultProps` to ' +
+          'a lazy component import. Either specify them where the component ' +
+          'is defined, or create a wrapping component around it.',
+      ],
       {withoutStack: true},
     );
 
@@ -742,14 +743,15 @@ describe('ReactLazy', () => {
     await waitForAll(['Loading...']);
     expect(root).not.toMatchRenderedOutput('Hi Bye');
 
-    await expect(async () => {
-      await act(() => resolveFakeImport(T));
-      assertLog(['Hi Bye']);
-    }).toErrorDev(
+    await act(() => resolveFakeImport(T));
+    assertLog(['Hi Bye']);
+    assertConsoleErrorDev([
       'T: Support for defaultProps ' +
         'will be removed from function components in a future major ' +
-        'release. Use JavaScript default parameters instead.',
-    );
+        'release. Use JavaScript default parameters instead.\n' +
+        '    in T (at **)\n' +
+        '    in Suspense (at **)',
+    ]);
 
     expect(root).toMatchRenderedOutput('Hi Bye');
 
@@ -1026,11 +1028,13 @@ describe('ReactLazy', () => {
     expect(root).not.toMatchRenderedOutput('Inner default text');
 
     // Mount
-    await expect(async () => {
-      await act(() => resolveFakeImport(T));
-      assertLog(['Inner default text']);
-    }).toErrorDev([
-      'T: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.',
+    await act(() => resolveFakeImport(T));
+    assertLog(['Inner default text']);
+    assertConsoleErrorDev([
+      'T: Support for defaultProps will be removed from function components in a future major release. ' +
+        'Use JavaScript default parameters instead.\n' +
+        '    in T (at **)\n' +
+        '    in Suspense (at **)',
     ]);
     expect(root).toMatchRenderedOutput('Inner default text');
 
@@ -1063,13 +1067,19 @@ describe('ReactLazy', () => {
     await waitForAll(['Started loading', 'Loading...']);
     expect(root).not.toMatchRenderedOutput(AB
);
 
-    await expect(async () => {
-      await act(() => resolveFakeImport(Foo));
-      assertLog(['A', 'B']);
-    }).toErrorDev(
-      (gate(flags => flags.enableOwnerStacks) ? '' : '    in Text (at **)\n') +
-        '    in Foo (at **)',
-    );
+    await act(() => resolveFakeImport(Foo));
+    assertLog(['A', 'B']);
+    assertConsoleErrorDev([
+      'Each child in a list should have a unique "key" prop.\n' +
+        '\n' +
+        'Check the render method of `Foo`. ' +
+        'See https://react.dev/link/warning-keys for more information.\n' +
+        (gate(flags => flags.enableOwnerStacks)
+          ? '    in Foo (at **)'
+          : '    in Text (at **)\n' +
+            '    in Foo (at **)\n' +
+            '    in Suspense (at **)'),
+    ]);
     expect(root).toMatchRenderedOutput(AB
);
   });
 
@@ -1143,11 +1153,12 @@ describe('ReactLazy', () => {
     expect(root).not.toMatchRenderedOutput('4');
 
     // Mount
-    await expect(async () => {
-      await act(() => resolveFakeImport(Add));
-    }).toErrorDev(
-      'Unknown: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
-    );
+    await act(() => resolveFakeImport(Add));
+    assertConsoleErrorDev([
+      'Unknown: Support for defaultProps will be removed from memo components in a future major release. ' +
+        'Use JavaScript default parameters instead.\n' +
+        '    in Suspense (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('4');
 
     // Update (shallowly equal)
@@ -1231,11 +1242,14 @@ describe('ReactLazy', () => {
     expect(root).not.toMatchRenderedOutput('4');
 
     // Mount
-    await expect(async () => {
-      await act(() => resolveFakeImport(Add));
-    }).toErrorDev([
-      'Memo: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
-      'Unknown: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
+    await act(() => resolveFakeImport(Add));
+    assertConsoleErrorDev([
+      'Memo: Support for defaultProps will be removed from memo components in a future major release. ' +
+        'Use JavaScript default parameters instead.\n' +
+        '    in Suspense (at **)',
+      'Unknown: Support for defaultProps will be removed from memo components in a future major release. ' +
+        'Use JavaScript default parameters instead.\n' +
+        '    in Suspense (at **)',
     ]);
     expect(root).toMatchRenderedOutput('4');
 
diff --git a/packages/react-reconciler/src/__tests__/ReactMemo-test.js b/packages/react-reconciler/src/__tests__/ReactMemo-test.js
index 5fdf14af4d37b..2a0c21d8dd9a4 100644
--- a/packages/react-reconciler/src/__tests__/ReactMemo-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactMemo-test.js
@@ -19,6 +19,7 @@ let Scheduler;
 let act;
 let waitForAll;
 let assertLog;
+let assertConsoleErrorDev;
 
 describe('memo', () => {
   beforeEach(() => {
@@ -33,6 +34,7 @@ describe('memo', () => {
     const InternalTestUtils = require('internal-test-utils');
     waitForAll = InternalTestUtils.waitForAll;
     assertLog = InternalTestUtils.assertLog;
+    assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
   });
 
   function Text(props) {
@@ -397,17 +399,19 @@ describe('memo', () => {
         // The final layer uses memo() from test fixture (which might be lazy).
         Counter = memo(Counter);
 
-        await expect(async () => {
-          await act(() => {
-            ReactNoop.render(
-              }>
-                
-              ,
-            );
-          });
-          assertLog(['Loading...', 15]);
-        }).toErrorDev([
-          'Counter: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.',
+        await act(() => {
+          ReactNoop.render(
+            }>
+              
+            ,
+          );
+        });
+        assertLog(['Loading...', 15]);
+        assertConsoleErrorDev([
+          'Counter: Support for defaultProps will be removed from memo components in a future major release. ' +
+            'Use JavaScript default parameters instead.\n' +
+            (label === 'lazy' ? '' : '    in Indirection (at **)\n') +
+            '    in Suspense (at **)',
         ]);
         expect(ReactNoop).toMatchRenderedOutput();
 
@@ -431,17 +435,23 @@ describe('memo', () => {
       });
 
       it('warns if the first argument is undefined', () => {
-        expect(() => memo()).toErrorDev(
-          'memo: The first argument must be a component. Instead ' +
-            'received: undefined',
+        memo();
+        assertConsoleErrorDev(
+          [
+            'memo: The first argument must be a component. Instead ' +
+              'received: undefined',
+          ],
           {withoutStack: true},
         );
       });
 
       it('warns if the first argument is null', () => {
-        expect(() => memo(null)).toErrorDev(
-          'memo: The first argument must be a component. Instead ' +
-            'received: null',
+        memo(null);
+        assertConsoleErrorDev(
+          [
+            'memo: The first argument must be a component. Instead ' +
+              'received: null',
+          ],
           {withoutStack: true},
         );
       });
@@ -458,16 +468,18 @@ describe('memo', () => {
         Outer.defaultProps = {outer: 100};
 
         const root = ReactNoop.createRoot();
-        await expect(async () => {
-          await act(() => {
-            root.render(
-              
-                
-              
,
-            );
-          });
-        }).toErrorDev([
-          'Support for defaultProps will be removed from memo component',
+        await act(() => {
+          root.render(
+            
+              
+            
,
+          );
+        });
+        assertConsoleErrorDev([
+          'Inner: ' +
+            'Support for defaultProps will be removed from memo components in a future major release. ' +
+            'Use JavaScript default parameters instead.\n' +
+            '    in div (at **)',
         ]);
         expect(root).toMatchRenderedOutput(111
);
 
@@ -559,14 +571,15 @@ describe('memo', () => {
           
         
,
       );
-      await expect(async () => {
-        await waitForAll([]);
-      }).toErrorDev(
+      await waitForAll([]);
+      assertConsoleErrorDev([
         'Each child in a list should have a unique "key" prop. ' +
           'See https://react.dev/link/warning-keys for more information.\n' +
           '    in span (at **)\n' +
-          '    in ',
-      );
+          (gate('enableOwnerStacks')
+            ? '    in **/ReactMemo-test.js:**:** (at **)'
+            : '    in p (at **)'),
+      ]);
     });
 
     it('should use the inner function name for the stack', async () => {
@@ -578,16 +591,15 @@ describe('memo', () => {
           
         ,
       );
-      await expect(async () => {
-        await waitForAll([]);
-      }).toErrorDev(
+      await waitForAll([]);
+      assertConsoleErrorDev([
         'Each child in a list should have a unique "key" prop.' +
           '\n\nCheck the top-level render call using . It was passed a child from Inner. ' +
           'See https://react.dev/link/warning-keys for more information.\n' +
           '    in span (at **)\n' +
           '    in Inner (at **)' +
           (gate(flags => flags.enableOwnerStacks) ? '' : '\n    in p (at **)'),
-      );
+      ]);
     });
 
     it('should use the inner name in the stack', async () => {
@@ -601,16 +613,15 @@ describe('memo', () => {
           
         ,
       );
-      await expect(async () => {
-        await waitForAll([]);
-      }).toErrorDev(
+      await waitForAll([]);
+      assertConsoleErrorDev([
         'Each child in a list should have a unique "key" prop.' +
           '\n\nCheck the top-level render call using . It was passed a child from Inner. ' +
           'See https://react.dev/link/warning-keys for more information.\n' +
           '    in span (at **)\n' +
           '    in Inner (at **)' +
           (gate(flags => flags.enableOwnerStacks) ? '' : '\n    in p (at **)'),
-      );
+      ]);
     });
 
     it('can use the outer displayName in the stack', async () => {
@@ -623,16 +634,15 @@ describe('memo', () => {
           
         ,
       );
-      await expect(async () => {
-        await waitForAll([]);
-      }).toErrorDev(
+      await waitForAll([]);
+      assertConsoleErrorDev([
         'Each child in a list should have a unique "key" prop.' +
           '\n\nCheck the top-level render call using . It was passed a child from Outer. ' +
           'See https://react.dev/link/warning-keys for more information.\n' +
           '    in span (at **)\n' +
           '    in Outer (at **)' +
           (gate(flags => flags.enableOwnerStacks) ? '' : '\n    in p (at **)'),
-      );
+      ]);
     });
 
     it('should prefer the inner to the outer displayName in the stack', async () => {
@@ -647,16 +657,15 @@ describe('memo', () => {
           
         ,
       );
-      await expect(async () => {
-        await waitForAll([]);
-      }).toErrorDev(
+      await waitForAll([]);
+      assertConsoleErrorDev([
         'Each child in a list should have a unique "key" prop.' +
           '\n\nCheck the top-level render call using . It was passed a child from Inner. ' +
           'See https://react.dev/link/warning-keys for more information.\n' +
           '    in span (at **)\n' +
           '    in Inner (at **)' +
           (gate(flags => flags.enableOwnerStacks) ? '' : '\n    in p (at **)'),
-      );
+      ]);
     });
   }
 });
diff --git a/packages/react-reconciler/src/__tests__/ReactNewContext-test.js b/packages/react-reconciler/src/__tests__/ReactNewContext-test.js
index b8fbca8339f5b..58cb2f9e648b5 100644
--- a/packages/react-reconciler/src/__tests__/ReactNewContext-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactNewContext-test.js
@@ -861,8 +861,11 @@ describe('ReactNewContext', () => {
         ,
       );
 
-      await expect(async () => await waitForAll([])).toErrorDev(
-        'The `value` prop is required for the ``. Did you misspell it or forget to pass it?',
+      await waitForAll([]);
+      assertConsoleErrorDev(
+        [
+          'The `value` prop is required for the ``. Did you misspell it or forget to pass it?',
+        ],
         {
           withoutStack: true,
         },
@@ -1036,7 +1039,9 @@ describe('ReactNewContext', () => {
       );
       await waitForAll(['LegacyProvider', 'App', 'Child']);
       assertConsoleErrorDev([
-        'LegacyProvider uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
+        'LegacyProvider uses the legacy childContextTypes API which will soon be removed. ' +
+          'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+          '    in LegacyProvider (at **)',
       ]);
       expect(ReactNoop).toMatchRenderedOutput();
 
@@ -1320,9 +1325,16 @@ describe('ReactNewContext', () => {
       }
 
       ReactNoop.render();
-      await expect(async () => await waitForAll([])).toErrorDev([
-        'Context can only be read while React is rendering',
-        'Cannot update during an existing state transition',
+      await waitForAll([]);
+      assertConsoleErrorDev([
+        'Cannot update during an existing state transition (such as within `render`). ' +
+          'Render methods should be a pure function of props and state.\n' +
+          '    in Cls (at **)',
+        'Context can only be read while React is rendering. ' +
+          'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
+          'In function components, you can read it directly in the function body, ' +
+          'but not inside Hooks like useReducer() or useMemo().\n' +
+          '    in Cls (at **)',
       ]);
     });
   });
@@ -1353,10 +1365,12 @@ describe('ReactNewContext', () => {
         return useContext(Context.Consumer);
       }
       ReactNoop.render();
-      await expect(async () => await waitForAll([])).toErrorDev(
+      await waitForAll([]);
+      assertConsoleErrorDev([
         'Calling useContext(Context.Consumer) is not supported and will cause bugs. ' +
-          'Did you mean to call useContext(Context) instead?',
-      );
+          'Did you mean to call useContext(Context) instead?\n' +
+          '    in Foo (at **)',
+      ]);
     });
 
     // Context consumer bails out on propagating "deep" updates when `value` hasn't changed.
diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseCallback-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseCallback-test.js
index 6da6ef7573fd9..921c9666a935e 100644
--- a/packages/react-reconciler/src/__tests__/ReactSuspenseCallback-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactSuspenseCallback-test.js
@@ -13,6 +13,7 @@ let React;
 let ReactNoop;
 let waitForAll;
 let act;
+let assertConsoleErrorDev;
 
 describe('ReactSuspense', () => {
   beforeEach(() => {
@@ -24,6 +25,7 @@ describe('ReactSuspense', () => {
     const InternalTestUtils = require('internal-test-utils');
     waitForAll = InternalTestUtils.waitForAll;
     act = InternalTestUtils.act;
+    assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
   });
 
   function createThenable() {
@@ -57,10 +59,10 @@ describe('ReactSuspense', () => {
     );
 
     ReactNoop.render(elementBadType);
-    await expect(async () => await waitForAll([])).toErrorDev(
-      ['Unexpected type for suspenseCallback.'],
-      {withoutStack: true},
-    );
+    await waitForAll([]);
+    assertConsoleErrorDev(['Unexpected type for suspenseCallback.'], {
+      withoutStack: true,
+    });
 
     const elementMissingCallback = (
       
@@ -69,7 +71,8 @@ describe('ReactSuspense', () => {
     );
 
     ReactNoop.render(elementMissingCallback);
-    await expect(async () => await waitForAll([])).toErrorDev([]);
+    await waitForAll([]);
+    assertConsoleErrorDev([]);
   });
 
   // @gate enableSuspenseCallback
diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js
index 63c398a657b09..7cfe72dfc4ec8 100644
--- a/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js
@@ -18,6 +18,7 @@ let SuspenseList;
 let waitForAll;
 let assertLog;
 let waitFor;
+let assertConsoleErrorDev;
 
 describe('ReactSuspenseList', () => {
   beforeEach(() => {
@@ -37,6 +38,7 @@ describe('ReactSuspenseList', () => {
     assertLog = InternalTestUtils.assertLog;
     waitFor = InternalTestUtils.waitFor;
     act = InternalTestUtils.act;
+    assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
   });
 
   function Text(props) {
@@ -72,11 +74,10 @@ describe('ReactSuspenseList', () => {
       );
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactNoop.render();
-      });
-    }).toErrorDev([
+    await act(() => {
+      ReactNoop.render();
+    });
+    assertConsoleErrorDev([
       '"something" is not a supported revealOrder on ' +
         '. Did you mean "together", "forwards" or "backwards"?' +
         '\n    in SuspenseList (at **)' +
@@ -94,11 +95,10 @@ describe('ReactSuspenseList', () => {
       );
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactNoop.render();
-      });
-    }).toErrorDev([
+    await act(() => {
+      ReactNoop.render();
+    });
+    assertConsoleErrorDev([
       '"TOGETHER" is not a valid value for revealOrder on ' +
         '. Use lowercase "together" instead.' +
         '\n    in SuspenseList (at **)' +
@@ -116,11 +116,10 @@ describe('ReactSuspenseList', () => {
       );
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactNoop.render();
-      });
-    }).toErrorDev([
+    await act(() => {
+      ReactNoop.render();
+    });
+    assertConsoleErrorDev([
       '"forward" is not a valid value for revealOrder on ' +
         '. React uses the -s suffix in the spelling. ' +
         'Use "forwards" instead.' +
@@ -147,15 +146,14 @@ describe('ReactSuspenseList', () => {
     // No warning
     await waitForAll([]);
 
-    await expect(async () => {
-      await act(() => {
-        ReactNoop.render(
-          
-            Child
-          ,
-        );
-      });
-    }).toErrorDev([
+    await act(() => {
+      ReactNoop.render(
+        
+          Child
+        ,
+      );
+    });
+    assertConsoleErrorDev([
       'A single row was passed to a . ' +
         'This is not useful since it needs multiple rows. ' +
         'Did you mean to pass multiple children or an array?' +
@@ -174,11 +172,10 @@ describe('ReactSuspenseList', () => {
       );
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactNoop.render();
-      });
-    }).toErrorDev([
+    await act(() => {
+      ReactNoop.render();
+    });
+    assertConsoleErrorDev([
       'A single row was passed to a . ' +
         'This is not useful since it needs multiple rows. ' +
         'Did you mean to pass multiple children or an array?' +
@@ -202,11 +199,10 @@ describe('ReactSuspenseList', () => {
       );
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactNoop.render();
-      });
-    }).toErrorDev([
+    await act(() => {
+      ReactNoop.render();
+    });
+    assertConsoleErrorDev([
       'A nested array was passed to row #0 in . ' +
         'Wrap it in an additional SuspenseList to configure its revealOrder: ' +
         ' ... ' +
@@ -1555,11 +1551,10 @@ describe('ReactSuspenseList', () => {
       );
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactNoop.render();
-      });
-    }).toErrorDev([
+    await act(() => {
+      ReactNoop.render();
+    });
+    assertConsoleErrorDev([
       '"collapse" is not a supported value for tail on ' +
         '. Did you mean "collapsed" or "hidden"?' +
         '\n    in SuspenseList (at **)' +
@@ -1577,11 +1572,10 @@ describe('ReactSuspenseList', () => {
       );
     }
 
-    await expect(async () => {
-      await act(() => {
-        ReactNoop.render();
-      });
-    }).toErrorDev([
+    await act(() => {
+      ReactNoop.render();
+    });
+    assertConsoleErrorDev([
       ' is only valid if ' +
         'revealOrder is "forwards" or "backwards". ' +
         'Did you mean to specify revealOrder="forwards"?' +
diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js
index 0dcf0eb4705ee..79968949e3d99 100644
--- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js
@@ -1979,7 +1979,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
       ReactNoop.render();
     });
 
-    // TODO: assert toErrorDev() when the warning is implemented again.
+    // TODO: assertConsoleErrorDev() when the warning is implemented again.
     await act(() => {
       ReactNoop.flushSync(() => _setShow(true));
     });
@@ -2006,7 +2006,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
       ReactNoop.render();
     });
 
-    // TODO: assert toErrorDev() when the warning is implemented again.
+    // TODO: assertConsoleErrorDev() when the warning is implemented again.
     await act(() => {
       ReactNoop.flushSync(() => show());
     });
@@ -2076,7 +2076,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
         ReactNoop.render();
       });
 
-      // TODO: assert toErrorDev() when the warning is implemented again.
+      // TODO: assertConsoleErrorDev() when the warning is implemented again.
       await act(() => {
         ReactNoop.flushSync(() => _setShow(true));
       });
diff --git a/packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js b/packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js
index 7a850325e9f2c..64d51a1ff3cd9 100644
--- a/packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactTransitionTracing-test.js
@@ -14,6 +14,7 @@ let Scheduler;
 let act;
 let waitForAll;
 let assertLog;
+let assertConsoleErrorDev;
 
 let getCacheForType;
 let useState;
@@ -43,11 +44,11 @@ describe('ReactInteractionTracing', () => {
     ReactNoop = require('react-noop-renderer');
     Scheduler = require('scheduler');
 
-    act = require('internal-test-utils').act;
-
     const InternalTestUtils = require('internal-test-utils');
+    act = InternalTestUtils.act;
     waitForAll = InternalTestUtils.waitForAll;
     assertLog = InternalTestUtils.assertLog;
+    assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
 
     useState = React.useState;
     startTransition = React.startTransition;
@@ -1412,14 +1413,12 @@ describe('ReactInteractionTracing', () => {
       root.render();
       ReactNoop.expire(1000);
       await advanceTimers(1000);
-      await expect(
-        async () =>
-          await waitForAll([
-            'Suspend [Page Two]',
-            'Loading...',
-            'onMarkerIncomplete(transition one, marker one, 1000, [{endTime: 3000, name: marker one, newName: marker two, type: marker}])',
-          ]),
-      ).toErrorDev('');
+
+      await waitForAll([
+        'Suspend [Page Two]',
+        'Loading...',
+        'onMarkerIncomplete(transition one, marker one, 1000, [{endTime: 3000, name: marker one, newName: marker two, type: marker}])',
+      ]);
 
       resolveText('Page Two');
       ReactNoop.expire(1000);
@@ -2220,17 +2219,18 @@ describe('ReactInteractionTracing', () => {
       );
       ReactNoop.expire(1000);
       await advanceTimers(1000);
-      await expect(async () => {
-        // onMarkerComplete shouldn't be called for transitions with
-        // new keys
-        await waitForAll([
-          'two',
-          'onTransitionStart(transition two, 1000)',
-          'onTransitionComplete(transition two, 1000, 2000)',
-        ]);
-      }).toErrorDev(
-        'Changing the name of a tracing marker after mount is not supported.',
-      );
+      // onMarkerComplete shouldn't be called for transitions with
+      // new keys
+      await waitForAll([
+        'two',
+        'onTransitionStart(transition two, 1000)',
+        'onTransitionComplete(transition two, 1000, 2000)',
+      ]);
+      assertConsoleErrorDev([
+        'Changing the name of a tracing marker after mount is not supported. ' +
+          'To remount the tracing marker, pass it a new key.\n' +
+          '    in App (at **)',
+      ]);
       startTransition(
         () => root.render(),
         {
diff --git a/packages/react-reconciler/src/__tests__/ReactUse-test.js b/packages/react-reconciler/src/__tests__/ReactUse-test.js
index 97d1df55d57dc..a120d6f250c9e 100644
--- a/packages/react-reconciler/src/__tests__/ReactUse-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactUse-test.js
@@ -27,6 +27,7 @@ let waitForPaint;
 let assertLog;
 let waitForAll;
 let waitForMicrotasks;
+let assertConsoleErrorDev;
 
 describe('ReactUse', () => {
   beforeEach(() => {
@@ -51,6 +52,7 @@ describe('ReactUse', () => {
     waitForPaint = InternalTestUtils.waitForPaint;
     waitFor = InternalTestUtils.waitFor;
     waitForMicrotasks = InternalTestUtils.waitForMicrotasks;
+    assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
 
     pendingTextRequests = new Map();
   });
@@ -246,16 +248,19 @@ describe('ReactUse', () => {
     }
 
     const root = ReactNoop.createRoot();
-    await expect(async () => {
-      await act(() => {
-        startTransition(() => {
-          root.render();
-        });
+    await act(() => {
+      startTransition(() => {
+        root.render();
       });
-    }).toErrorDev([
+    });
+    assertConsoleErrorDev([
       'A component was suspended by an uncached promise. Creating ' +
         'promises inside a Client Component or hook is not yet ' +
-        'supported, except via a Suspense-compatible library or framework.',
+        'supported, except via a Suspense-compatible library or framework.\n' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '    in Async (at **)\n' + '    in Suspense (at **)\n') +
+        '    in App (at **)',
     ]);
     assertLog(['ABC']);
     expect(root).toMatchRenderedOutput('ABC');
@@ -416,19 +421,30 @@ describe('ReactUse', () => {
     }
 
     const root = ReactNoop.createRoot();
-    await expect(async () => {
-      await act(() => {
-        startTransition(() => {
-          root.render();
-        });
+    await act(() => {
+      startTransition(() => {
+        root.render();
       });
-    }).toErrorDev([
+    });
+    assertConsoleErrorDev([
       'A component was suspended by an uncached promise. Creating ' +
         'promises inside a Client Component or hook is not yet ' +
-        'supported, except via a Suspense-compatible library or framework.',
+        'supported, except via a Suspense-compatible library or framework.\n' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '    in Async (at **)\n' +
+            '    in ErrorBoundary (at **)\n' +
+            '    in Suspense (at **)\n') +
+        '    in App (at **)',
       'A component was suspended by an uncached promise. Creating ' +
         'promises inside a Client Component or hook is not yet ' +
-        'supported, except via a Suspense-compatible library or framework.',
+        'supported, except via a Suspense-compatible library or framework.\n' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '    in Async (at **)\n' +
+            '    in ErrorBoundary (at **)\n' +
+            '    in Suspense (at **)\n') +
+        '    in App (at **)',
     ]);
     assertLog([
       // First attempt. The uncached promise suspends.
@@ -560,6 +576,7 @@ describe('ReactUse', () => {
           'allowed and can lead to unexpected behavior. To handle errors ' +
           'triggered by `use`, wrap your component in a error boundary.',
       );
+      console.error.mockRestore();
     }
   });
 
@@ -596,6 +613,13 @@ describe('ReactUse', () => {
       resolveTextRequests('Async');
     });
     assertLog(['Async text requested [Async]', 'Async']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '     in App (at **)\n' +
+        '     in Suspense (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('Async');
   });
 
@@ -639,6 +663,13 @@ describe('ReactUse', () => {
     });
     // This time it finishes because it was during a retry.
     assertLog(['Async text requested [Async]', 'Async']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '     in App (at **)\n' +
+        '     in Suspense (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('Async');
   });
 
@@ -886,6 +917,7 @@ describe('ReactUse', () => {
         root.render();
       });
     });
+
     // Suspends while we wait for the async service to respond.
     assertLog(['Compute uppercase: Hello', 'Async text requested [HELLO!]']);
     expect(root).toMatchRenderedOutput(null);
@@ -894,6 +926,13 @@ describe('ReactUse', () => {
     await act(() => {
       resolveTextRequests('HELLO!');
     });
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in ExcitingText (at **)',
+    ]);
+
     assertLog([
       // We shouldn't run the uppercase computation again, because we can reuse
       // the computation from the previous attempt.
@@ -931,6 +970,13 @@ describe('ReactUse', () => {
       resolveTextRequests('apple');
     });
     assertLog(['Async text requested [apple]', 'apple carrot']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in Kitchen (at **)',
+    ]);
+
     expect(root).toMatchRenderedOutput('apple carrot');
 
     // Update the state variable after the use().
@@ -945,6 +991,13 @@ describe('ReactUse', () => {
       resolveTextRequests('apple');
     });
     assertLog(['Async text requested [apple]', 'apple dill']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in Kitchen (at **)',
+    ]);
+
     expect(root).toMatchRenderedOutput('apple dill');
 
     // Update the state variable before the use(). The second state is maintained.
@@ -959,6 +1012,12 @@ describe('ReactUse', () => {
       resolveTextRequests('banana');
     });
     assertLog(['Async text requested [banana]', 'banana dill']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in Kitchen (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('banana dill');
   });
 
@@ -987,6 +1046,12 @@ describe('ReactUse', () => {
       resolveTextRequests('aguacate');
     });
     assertLog(['Async text requested [aguacate]', 'aguacate abogado']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in Lexicon (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('aguacate abogado');
 
     // Now update the state.
@@ -1001,6 +1066,12 @@ describe('ReactUse', () => {
       resolveTextRequests('aguacate');
     });
     assertLog(['Async text requested [aguacate]', 'aguacate avocat']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in Lexicon (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('aguacate avocat');
   });
 
@@ -1141,6 +1212,13 @@ describe('ReactUse', () => {
       'Async text requested [B]',
       '(Loading B...)',
     ]);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in AsyncText (at **)\n' +
+        '    in Suspense (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('A(Loading B...)');
 
     await act(() => {
@@ -1161,6 +1239,14 @@ describe('ReactUse', () => {
       'Async text requested [C]',
       '(Loading C...)',
     ]);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in AsyncText (at **)\n' +
+        '    in Suspense (at **)\n' +
+        '    in Suspense (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('AB(Loading C...)');
 
     await act(() => {
@@ -1173,6 +1259,15 @@ describe('ReactUse', () => {
       resolveTextRequests('C');
     });
     assertLog(['Async text requested [C]', 'C']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in AsyncText (at **)\n' +
+        '    in Suspense (at **)\n' +
+        '    in Suspense (at **)\n' +
+        '    in Suspense (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('ABC');
   });
 
@@ -1202,6 +1297,22 @@ describe('ReactUse', () => {
       });
     });
     assertLog(['A1']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '    in Async (at **)\n' + '    in Suspense (at **)\n') +
+        '    in App (at **)',
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '    in Async (at **)\n' + '    in Suspense (at **)\n') +
+        '    in App (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('A1');
   });
 
@@ -1231,7 +1342,12 @@ describe('ReactUse', () => {
       });
     });
     assertLog(['Async text requested [Hi]']);
-
+    assertConsoleErrorDev([
+      'async/await is not yet supported in Client Components, only Server Components. ' +
+        "This error is often caused by accidentally adding `'use client'` " +
+        'to a module that was originally written for the server.\n' +
+        '    in App (at **)',
+    ]);
     await act(() => resolveTextRequests('Hi'));
     assertLog([
       // TODO: We shouldn't have to replay the function body again. Skip
@@ -1239,6 +1355,12 @@ describe('ReactUse', () => {
       'Async text requested [Hi]',
       'Hi',
     ]);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in App (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('Hi');
   });
 
@@ -1268,6 +1390,12 @@ describe('ReactUse', () => {
       'Async text requested [Hi]',
       'Hi',
     ]);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in App (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('Hi');
   });
 
@@ -1314,6 +1442,16 @@ describe('ReactUse', () => {
       });
     });
     assertLog(['A', 'Mount: A']);
+    assertConsoleErrorDev([
+      'async/await is not yet supported in Client Components, only Server Components. ' +
+        "This error is often caused by accidentally adding `'use client'` " +
+        'to a module that was originally written for the server.\n' +
+        '    in App (at **)',
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in App (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('A');
 
     // Update the child's props. It should not remount.
@@ -1323,6 +1461,12 @@ describe('ReactUse', () => {
       });
     });
     assertLog(['B', 'Mount: B']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in App (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('B');
   });
 
@@ -1535,6 +1679,16 @@ describe('ReactUse', () => {
       });
     });
     assertLog(['Async']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '    in **/ReactUse-test.js:**:** (at **)\n' +
+            '    in Suspense (at **)\n') +
+        '    in App (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('Async');
     expect(ref.current).toBe(asyncInstance);
   });
@@ -1563,6 +1717,16 @@ describe('ReactUse', () => {
       });
     });
     assertLog(['Async']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '    in **/ReactUse-test.js:**:** (at **)\n' +
+            '    in Suspense (at **)\n') +
+        '    in App (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('Async');
 
     // Update to the same value
@@ -1582,6 +1746,16 @@ describe('ReactUse', () => {
       });
     });
     assertLog(['Async!']);
+    assertConsoleErrorDev([
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '    in **/ReactUse-test.js:**:** (at **)\n' +
+            '    in Suspense (at **)\n') +
+        '    in App (at **)',
+    ]);
     expect(root).toMatchRenderedOutput('Async!');
   });
 
@@ -1631,6 +1805,41 @@ describe('ReactUse', () => {
       });
     });
     assertLog(['Async (function component)', 'Async (memo component)']);
+    assertConsoleErrorDev([
+      'ContextProvider uses the legacy childContextTypes API which will soon be removed. ' +
+        'Use React.createContext() instead. (https://react.dev/link/legacy-context)\n' +
+        (gate('enableOwnerStacks') ? '' : '    in ContextProvider (at **)\n') +
+        '    in App (at **)',
+      'Async uses the legacy contextTypes API which will be removed soon. ' +
+        'Use React.createContext() with React.useContext() instead. (https://react.dev/link/legacy-context)\n' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '    in Async (at **)\n' +
+            '    in div (at **)\n' +
+            '    in Suspense (at **)\n' +
+            '    in ContextProvider (at **)\n') +
+        '    in App (at **)',
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '    in Async (at **)\n' +
+            '    in div (at **)\n' +
+            '    in Suspense (at **)\n' +
+            '    in ContextProvider (at **)\n') +
+        '    in App (at **)',
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        (gate('enableOwnerStacks')
+          ? ''
+          : '    in Async (at **)\n' +
+            '    in div (at **)\n' +
+            '    in Suspense (at **)\n' +
+            '    in ContextProvider (at **)\n') +
+        '    in App (at **)',
+    ]);
     expect(root).toMatchRenderedOutput(
       <>
         Async (function component)
@@ -1698,19 +1907,19 @@ describe('ReactUse', () => {
     }
 
     const root = ReactNoop.createRoot();
-    await expect(async () => {
-      await act(() => {
-        root.render(
-          
-            
-          ,
-        );
-      });
-    }).toErrorDev([
-      'async/await is not yet supported in Client Components, only ' +
-        'Server Components. This error is often caused by accidentally ' +
-        "adding `'use client'` to a module that was originally written " +
-        'for the server.',
+    await act(async () => {
+      root.render(
+        
+          
+        ,
+      );
+    });
+    assertConsoleErrorDev([
+      'async/await is not yet supported in Client Components, only Server Components. ' +
+        "This error is often caused by accidentally adding `'use client'` " +
+        'to a module that was originally written for the server.\n' +
+        '    in AsyncClientComponent (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in ErrorBoundary (at **)'),
     ]);
     assertLog([
       'async/await is not yet supported in Client Components, only Server ' +
@@ -1750,19 +1959,19 @@ describe('ReactUse', () => {
     }
 
     const root = ReactNoop.createRoot();
-    await expect(async () => {
-      await act(() => {
-        root.render(
-          
-            
-          ,
-        );
-      });
-    }).toErrorDev([
-      'async/await is not yet supported in Client Components, only ' +
-        'Server Components. This error is often caused by accidentally ' +
-        "adding `'use client'` to a module that was originally written " +
-        'for the server.',
+    await act(async () => {
+      root.render(
+        
+          
+        ,
+      );
+    });
+    assertConsoleErrorDev([
+      'async/await is not yet supported in Client Components, only Server Components. ' +
+        "This error is often caused by accidentally adding `'use client'` " +
+        'to a module that was originally written for the server.\n' +
+        '    in AsyncClientComponent (at **)' +
+        (gate('enableOwnerStacks') ? '' : '\n    in ErrorBoundary (at **)'),
     ]);
     assertLog([
       'async/await is not yet supported in Client Components, only Server ' +
@@ -1792,25 +2001,25 @@ describe('ReactUse', () => {
       }
 
       const root = ReactNoop.createRoot();
-      await expect(async () => {
-        await act(() => {
-          startTransition(() => {
-            root.render();
-          });
+      await act(() => {
+        startTransition(() => {
+          root.render();
         });
-      }).toErrorDev([
+      });
+      assertConsoleErrorDev([
         // Note: This used to log a different warning about not using hooks
         // inside async components, like we do on the server. Since then, we
         // decided to warn for _any_ async client component regardless of
         // whether the update is sync. But if we ever add back support for async
         // client components, we should add back the hook warning.
-        'async/await is not yet supported in Client Components, only Server ' +
-          'Components. This error is often caused by accidentally adding ' +
-          "`'use client'` to a module that was originally written for " +
-          'the server.',
-        'A component was suspended by an uncached promise. Creating ' +
-          'promises inside a Client Component or hook is not yet ' +
-          'supported, except via a Suspense-compatible library or framework.',
+        'async/await is not yet supported in Client Components, only Server Components. ' +
+          "This error is often caused by accidentally adding `'use client'` " +
+          'to a module that was originally written for the server.\n' +
+          '    in AsyncClientComponent (at **)',
+        'A component was suspended by an uncached promise. ' +
+          'Creating promises inside a Client Component or hook is not yet supported, ' +
+          'except via a Suspense-compatible library or framework.\n' +
+          '    in AsyncClientComponent (at **)',
       ]);
     },
   );
@@ -1824,28 +2033,29 @@ describe('ReactUse', () => {
     }
 
     const root = ReactNoop.createRoot();
-    await expect(async () => {
-      await act(() => {
-        startTransition(() => {
-          root.render();
-        });
+    await act(() => {
+      startTransition(() => {
+        root.render();
       });
-    }).toErrorDev([
+    });
+    assertConsoleErrorDev([
       // Note: This used to log a different warning about not using hooks
       // inside async components, like we do on the server. Since then, we
       // decided to warn for _any_ async client component regardless of
       // whether the update is sync. But if we ever add back support for async
       // client components, we should add back the hook warning.
-      'async/await is not yet supported in Client Components, only Server ' +
-        'Components. This error is often caused by accidentally adding ' +
-        "`'use client'` to a module that was originally written for " +
-        'the server.',
-      'A component was suspended by an uncached promise. Creating ' +
-        'promises inside a Client Component or hook is not yet ' +
-        'supported, except via a Suspense-compatible library or framework.',
-      'A component was suspended by an uncached promise. Creating ' +
-        'promises inside a Client Component or hook is not yet ' +
-        'supported, except via a Suspense-compatible library or framework.',
+      'async/await is not yet supported in Client Components, only Server Components. ' +
+        "This error is often caused by accidentally adding `'use client'` " +
+        'to a module that was originally written for the server.\n' +
+        '    in AsyncClientComponent (at **)',
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in AsyncClientComponent (at **)',
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in AsyncClientComponent (at **)',
     ]);
   });
 
@@ -1863,38 +2073,41 @@ describe('ReactUse', () => {
     }
 
     const root = ReactNoop.createRoot();
-    await expect(async () => {
-      await act(() => {
-        startTransition(() => {
-          root.render();
-        });
+    await act(() => {
+      startTransition(() => {
+        root.render();
       });
-    }).toErrorDev([
-      'async/await is not yet supported in Client Components, only ' +
-        'Server Components. This error is often caused by accidentally ' +
-        "adding `'use client'` to a module that was originally written " +
-        'for the server.',
+    });
+    assertConsoleErrorDev([
+      'async/await is not yet supported in Client Components, only Server Components. ' +
+        "This error is often caused by accidentally adding `'use client'` " +
+        'to a module that was originally written for the server.\n' +
+        '    in App (at **)',
     ]);
     assertLog(['Async text requested [Hi]']);
 
-    await expect(async () => {
-      await act(() => resolveTextRequests('Hi'));
-    }).toErrorDev([
+    await act(() => resolveTextRequests('Hi'));
+    assertConsoleErrorDev([
       // We get this warning because the generator's promise themselves are not cached.
-      'A component was suspended by an uncached promise. Creating ' +
-        'promises inside a Client Component or hook is not yet ' +
-        'supported, except via a Suspense-compatible library or framework.',
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in App (at **)',
     ]);
 
     assertLog(['Async text requested [World]']);
 
-    if (gate('enableSiblingPrerendering')) {
-      await expect(async () => {
-        await act(() => resolveTextRequests('World'));
-      }).toErrorDev(['A component was suspended by an uncached promise.']);
-    } else {
-      await act(() => resolveTextRequests('World'));
-    }
+    await act(() => resolveTextRequests('World'));
+    assertConsoleErrorDev(
+      gate('enableSiblingPrerendering')
+        ? [
+            'A component was suspended by an uncached promise. ' +
+              'Creating promises inside a Client Component or hook is not yet supported, ' +
+              'except via a Suspense-compatible library or framework.\n' +
+              '    in App (at **)',
+          ]
+        : [],
+    );
 
     assertLog(['Hi', 'World']);
     expect(root).toMatchRenderedOutput('Hi World');
@@ -1928,24 +2141,30 @@ describe('ReactUse', () => {
     });
     assertLog(['Async text requested [Hi]']);
 
-    await expect(async () => {
-      await act(() => resolveTextRequests('Hi'));
-    }).toErrorDev([
+    await act(() => resolveTextRequests('Hi'));
+    assertConsoleErrorDev([
       // We get this warning because the generator's promise themselves are not cached.
-      'A component was suspended by an uncached promise. Creating ' +
-        'promises inside a Client Component or hook is not yet ' +
-        'supported, except via a Suspense-compatible library or framework.',
+      'A component was suspended by an uncached promise. ' +
+        'Creating promises inside a Client Component or hook is not yet supported, ' +
+        'except via a Suspense-compatible library or framework.\n' +
+        '    in div (at **)\n' +
+        '    in App (at **)',
     ]);
 
     assertLog(['Async text requested [World]']);
 
-    if (gate('enableSiblingPrerendering')) {
-      await expect(async () => {
-        await act(() => resolveTextRequests('World'));
-      }).toErrorDev(['A component was suspended by an uncached promise.']);
-    } else {
-      await act(() => resolveTextRequests('World'));
-    }
+    await act(() => resolveTextRequests('World'));
+    assertConsoleErrorDev(
+      gate('enableSiblingPrerendering')
+        ? [
+            'A component was suspended by an uncached promise. ' +
+              'Creating promises inside a Client Component or hook is not yet supported, ' +
+              'except via a Suspense-compatible library or framework.\n' +
+              '    in div (at **)\n' +
+              '    in App (at **)',
+          ]
+        : [],
+    );
 
     assertLog(['Hi', 'World']);
     expect(root).toMatchRenderedOutput(Hi World
);