File tree Expand file tree Collapse file tree 3 files changed +51
-2
lines changed
dev-packages/e2e-tests/test-applications/nextjs-15
packages/nextjs/src/server Expand file tree Collapse file tree 3 files changed +51
-2
lines changed Original file line number Diff line number Diff line change
1
+ import * as Sentry from '@sentry/nextjs' ;
2
+ import { use } from 'react' ;
3
+ export const dynamic = 'force-dynamic' ;
4
+
5
+ export default async function Page ( ) {
6
+ try {
7
+ use ( fetch ( 'http://example.com/' ) ) ;
8
+ } catch ( e ) {
9
+ Sentry . captureException ( e ) ; // This error should not be reported
10
+ await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ; // Wait for any async event processors to run
11
+ await Sentry . flush ( ) ;
12
+ }
13
+
14
+ return < p > test</ p > ;
15
+ }
Original file line number Diff line number Diff line change
1
+ import { expect , test } from '@playwright/test' ;
2
+ import { waitForError , waitForTransaction } from '@sentry-internal/event-proxy-server' ;
3
+
4
+ test ( 'should not capture serverside suspense errors' , async ( { page } ) => {
5
+ const pageServerComponentTransactionPromise = waitForTransaction ( 'nextjs-15' , async transactionEvent => {
6
+ return transactionEvent ?. transaction === 'Page Server Component (/suspense-error)' ;
7
+ } ) ;
8
+
9
+ let errorEvent ;
10
+ waitForError ( 'nextjs-15' , async transactionEvent => {
11
+ return transactionEvent ?. transaction === 'Page Server Component (/suspense-error)' ;
12
+ } ) . then ( event => {
13
+ errorEvent = event ;
14
+ } ) ;
15
+
16
+ await page . goto ( `/suspense-error` ) ;
17
+
18
+ await page . waitForTimeout ( 5000 ) ;
19
+
20
+ const pageServerComponentTransaction = await pageServerComponentTransactionPromise ;
21
+ expect ( pageServerComponentTransaction ) . toBeDefined ( ) ;
22
+
23
+ expect ( errorEvent ) . toBeUndefined ( ) ;
24
+ } ) ;
Original file line number Diff line number Diff line change @@ -190,13 +190,23 @@ export function init(options: NodeOptions): void {
190
190
191
191
const originalException = hint . originalException ;
192
192
193
- const isReactControlFlowError =
193
+ const isPostponeError =
194
194
typeof originalException === 'object' &&
195
195
originalException !== null &&
196
196
'$$typeof' in originalException &&
197
197
originalException . $$typeof === Symbol . for ( 'react.postpone' ) ;
198
198
199
- if ( isReactControlFlowError ) {
199
+ if ( isPostponeError ) {
200
+ // Postpone errors are used for partial-pre-rendering (PPR)
201
+ return null ;
202
+ }
203
+
204
+ // We don't want to capture suspense errors as they are simply used by React/Next.js for control flow
205
+ const exceptionMessage = event . exception ?. values ?. [ 0 ] ?. value ;
206
+ if (
207
+ exceptionMessage ?. includes ( 'Suspense Exception: This is not a real error!' ) ||
208
+ exceptionMessage ?. includes ( 'Suspense Exception: This is not a real error, and should not leak' )
209
+ ) {
200
210
return null ;
201
211
}
202
212
You can’t perform that action at this time.
0 commit comments