From 621413ebfecce38c667ac0daad2679ee5b0b0f00 Mon Sep 17 00:00:00 2001 From: Andrei Borza Date: Tue, 19 May 2026 14:35:46 +0900 Subject: [PATCH 1/5] chore(nextjs): Skip flaky server-components test in dev mode Looks like Turbopack sometimes returns 404 for nested dynamic routes like /parametrized/[one]/beep/[two]. We drop 404 server transactions by default, causing timeouts in the test's `waitForTransaction`. We skip this test in dev mode for now. Closes: #20992 --- .../nextjs-16/tests/server-components.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16/tests/server-components.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-16/tests/server-components.test.ts index 81aa5c98288c..c62db823ff1a 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16/tests/server-components.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16/tests/server-components.test.ts @@ -1,7 +1,12 @@ import { expect, test } from '@playwright/test'; import { waitForTransaction } from '@sentry-internal/test-utils'; +import { isDevMode } from './isDevMode'; test('Sends a transaction for a request to app router with URL', async ({ page }) => { + // Turbopack dev mode intermittently 404s on nested dynamic routes, and the SDK + // drops 404 server transactions, so the waitForTransaction times out. + test.skip(isDevMode, 'Turbopack intermittently returns 404 for nested dynamic routes in dev mode'); + const serverComponentTransactionPromise = waitForTransaction('nextjs-16', transactionEvent => { return ( transactionEvent?.transaction === 'GET /parameterized/[one]/beep/[two]' && From 82e98c4b961aee7a17116f43e0799a9f5678077e Mon Sep 17 00:00:00 2001 From: Andrei Borza Date: Tue, 19 May 2026 15:54:43 +0900 Subject: [PATCH 2/5] Skip flaky route handler tests in nextjs-16 dev mode Turbopack intermittently returns 404 for dynamic routes like /route-handler/[xoxo]/... in dev mode, causing all route handler tests to time out waiting for Sentry events that never arrive. Skip the four affected tests in dev mode. Also removes now-dead dev-mode conditionals since the tests no longer run in that env. --- .../nextjs-16/tests/route-handler.test.ts | 32 ++++++------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16/tests/route-handler.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-16/tests/route-handler.test.ts index e37c39eb4dba..abba755f9b88 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16/tests/route-handler.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16/tests/route-handler.test.ts @@ -1,7 +1,10 @@ import test, { expect } from '@playwright/test'; import { waitForError, waitForTransaction } from '@sentry-internal/test-utils'; +import { isDevMode } from './isDevMode'; test('Should create a transaction for node route handlers', async ({ request }) => { + test.skip(isDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); + const routehandlerTransactionPromise = waitForTransaction('nextjs-16', async transactionEvent => { return transactionEvent?.transaction === 'GET /route-handler/[xoxo]/node'; }); @@ -13,11 +16,7 @@ test('Should create a transaction for node route handlers', async ({ request }) expect(routehandlerTransaction.contexts?.trace?.status).toBe('ok'); expect(routehandlerTransaction.contexts?.trace?.op).toBe('http.server'); - - // This is flaking on dev mode - if (process.env.TEST_ENV !== 'development' && process.env.TEST_ENV !== 'dev-turbopack') { - expect(routehandlerTransaction.contexts?.trace?.data?.['http.request.header.x_charly']).toBe('gomez'); - } + expect(routehandlerTransaction.contexts?.trace?.data?.['http.request.header.x_charly']).toBe('gomez'); }); test('Should create a transaction for edge route handlers', async ({ request }) => { @@ -41,6 +40,8 @@ test('Should create a transaction for edge route handlers', async ({ request }) test('Should report an error with a parameterized transaction name for a throwing route handler', async ({ request, }) => { + test.skip(isDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); + const errorEventPromise = waitForError('nextjs-16', errorEvent => { return errorEvent?.exception?.values?.some(value => value.value === 'route-handler-error') ?? false; }); @@ -63,23 +64,6 @@ test('Should report an error with a parameterized transaction name for a throwin // Error should carry the parameterized transaction name expect(errorEvent.transaction).toBe('GET /route-handler/[xoxo]/error'); - // On turbopack (no wrapping loader), the error goes through onRequestError which sets nextjs context. - // On webpack, the wrapping loader's error handler fires first and captures without nextjs context. - // The SDK deduplicates by error identity, so only the first capture survives. - if (process.env.TEST_ENV === 'development') { - expect(errorEvent.contexts?.nextjs).toEqual({ - route_type: 'route', - router_kind: 'App Router', - router_path: '/route-handler/[xoxo]/error', - request_path: '/route-handler/456/error', - }); - - expect(errorEvent.exception?.values?.[0]?.mechanism).toEqual({ - handled: false, - type: 'auto.function.nextjs.on_request_error', - }); - } - // Transaction should have parameterized name and internal_error status expect(transactionEvent.transaction).toBe('GET /route-handler/[xoxo]/error'); expect(transactionEvent.contexts?.trace?.status).toBe('internal_error'); @@ -88,6 +72,8 @@ test('Should report an error with a parameterized transaction name for a throwin test('Should set a parameterized transaction name on a captureMessage event in a route handler', async ({ request, }) => { + test.skip(isDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); + const messageEventPromise = waitForError('nextjs-16', event => { return event?.message === 'route-handler-message'; }); @@ -119,6 +105,8 @@ test('Should set a parameterized transaction name on a captureMessage event in a test('Should set a parameterized transaction name on a captureException event in a route handler', async ({ request, }) => { + test.skip(isDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); + const errorEventPromise = waitForError('nextjs-16', errorEvent => { return errorEvent?.exception?.values?.some(value => value.value === 'route-handler-capture-exception') ?? false; }); From d6166c33a91183e946e70789c53585a3276f8f81 Mon Sep 17 00:00:00 2001 From: Andrei Borza Date: Tue, 19 May 2026 15:54:47 +0900 Subject: [PATCH 3/5] Skip flaky route handler tests in nextjs-16-streaming dev mode Same Turbopack 404 issue as nextjs-16: dynamic routes under /route-handler/[xoxo]/... intermittently 404 in dev mode, so the three route handler tests time out waiting for events. --- .../nextjs-16-streaming/tests/route-handler.test.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/tests/route-handler.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/tests/route-handler.test.ts index be6be4c220b7..c494ac2530d4 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/tests/route-handler.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/tests/route-handler.test.ts @@ -1,7 +1,10 @@ import test, { expect } from '@playwright/test'; import { waitForError, waitForStreamedSpan, getSpanOp } from '@sentry-internal/test-utils'; +import { isDevMode } from './isDevMode'; test('Should create a streamed span for node route handlers', async ({ request }) => { + test.skip(isDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); + const rootSpanPromise = waitForStreamedSpan('nextjs-16-streaming', span => { return span.name === 'GET /route-handler/[xoxo]/node' && getSpanOp(span) === 'http.server' && span.is_segment; }); @@ -16,6 +19,8 @@ test('Should create a streamed span for node route handlers', async ({ request } }); test('Should report an error linked to the correct trace for a throwing route handler', async ({ request }) => { + test.skip(isDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); + const errorEventPromise = waitForError('nextjs-16-streaming', errorEvent => { return errorEvent?.exception?.values?.some(value => value.value === 'route-handler-error') ?? false; }); @@ -37,6 +42,8 @@ test('Should report an error linked to the correct trace for a throwing route ha test('Should set a parameterized transaction name on a captureMessage event in a route handler', async ({ request, }) => { + test.skip(isDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); + const messageEventPromise = waitForError('nextjs-16-streaming', event => { return event?.message === 'route-handler-message'; }); From e9b074bfa9378c3cb981d97908a706e4dd94c358 Mon Sep 17 00:00:00 2001 From: Andrei Borza Date: Tue, 19 May 2026 15:54:52 +0900 Subject: [PATCH 4/5] Skip flaky server-components test in nextjs-16-streaming dev mode Same Turbopack 404 issue: /parameterized/[one]/beep/[two] intermittently 404s in dev mode, so the streamed span test times out. --- .../nextjs-16-streaming/tests/server-components.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/tests/server-components.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/tests/server-components.test.ts index ba64953678b3..4855697e7753 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/tests/server-components.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/tests/server-components.test.ts @@ -1,7 +1,10 @@ import { expect, test } from '@playwright/test'; import { waitForStreamedSpan, waitForStreamedSpans, getSpanOp } from '@sentry-internal/test-utils'; +import { isDevMode } from './isDevMode'; test('Sends a streamed span for a request to app router with URL', async ({ page }) => { + test.skip(isDevMode, 'Turbopack intermittently returns 404 for nested dynamic routes in dev mode'); + const rootSpanPromise = waitForStreamedSpan('nextjs-16-streaming', span => { return span.name === 'GET /parameterized/[one]/beep/[two]' && span.is_segment; }); From c7bd25e4530e5b3f8267b193f4efbba1819328b9 Mon Sep 17 00:00:00 2001 From: Andrei Borza Date: Tue, 19 May 2026 16:26:17 +0900 Subject: [PATCH 5/5] Use isTurbopackDevMode for nextjs-16 dev mode skips isDevMode matches both TEST_ENV=development (turbopack) and TEST_ENV=development-webpack, which silently drops test coverage for the webpack dev variant where the Turbopack 404 issue doesn't apply. Add isTurbopackDevMode (exact match on 'development') and use it for all Turbopack-specific skips. Also skip the dynamic page test in server-components.test.ts (/nested-layout/[dynamic]) which has the same Turbopack 404 flake. --- .../test-applications/nextjs-16/tests/isDevMode.ts | 1 + .../nextjs-16/tests/route-handler.test.ts | 10 +++++----- .../nextjs-16/tests/server-components.test.ts | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16/tests/isDevMode.ts b/dev-packages/e2e-tests/test-applications/nextjs-16/tests/isDevMode.ts index d2be94232110..28f60f6f035c 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16/tests/isDevMode.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16/tests/isDevMode.ts @@ -1 +1,2 @@ export const isDevMode = !!process.env.TEST_ENV && process.env.TEST_ENV.includes('development'); +export const isTurbopackDevMode = process.env.TEST_ENV === 'development'; diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16/tests/route-handler.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-16/tests/route-handler.test.ts index abba755f9b88..6f7de6aeb14f 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16/tests/route-handler.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16/tests/route-handler.test.ts @@ -1,9 +1,9 @@ import test, { expect } from '@playwright/test'; import { waitForError, waitForTransaction } from '@sentry-internal/test-utils'; -import { isDevMode } from './isDevMode'; +import { isTurbopackDevMode } from './isDevMode'; test('Should create a transaction for node route handlers', async ({ request }) => { - test.skip(isDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); + test.skip(isTurbopackDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); const routehandlerTransactionPromise = waitForTransaction('nextjs-16', async transactionEvent => { return transactionEvent?.transaction === 'GET /route-handler/[xoxo]/node'; @@ -40,7 +40,7 @@ test('Should create a transaction for edge route handlers', async ({ request }) test('Should report an error with a parameterized transaction name for a throwing route handler', async ({ request, }) => { - test.skip(isDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); + test.skip(isTurbopackDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); const errorEventPromise = waitForError('nextjs-16', errorEvent => { return errorEvent?.exception?.values?.some(value => value.value === 'route-handler-error') ?? false; @@ -72,7 +72,7 @@ test('Should report an error with a parameterized transaction name for a throwin test('Should set a parameterized transaction name on a captureMessage event in a route handler', async ({ request, }) => { - test.skip(isDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); + test.skip(isTurbopackDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); const messageEventPromise = waitForError('nextjs-16', event => { return event?.message === 'route-handler-message'; @@ -105,7 +105,7 @@ test('Should set a parameterized transaction name on a captureMessage event in a test('Should set a parameterized transaction name on a captureException event in a route handler', async ({ request, }) => { - test.skip(isDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); + test.skip(isTurbopackDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); const errorEventPromise = waitForError('nextjs-16', errorEvent => { return errorEvent?.exception?.values?.some(value => value.value === 'route-handler-capture-exception') ?? false; diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16/tests/server-components.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-16/tests/server-components.test.ts index c62db823ff1a..b0eb803300b0 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16/tests/server-components.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16/tests/server-components.test.ts @@ -1,11 +1,9 @@ import { expect, test } from '@playwright/test'; import { waitForTransaction } from '@sentry-internal/test-utils'; -import { isDevMode } from './isDevMode'; +import { isTurbopackDevMode } from './isDevMode'; test('Sends a transaction for a request to app router with URL', async ({ page }) => { - // Turbopack dev mode intermittently 404s on nested dynamic routes, and the SDK - // drops 404 server transactions, so the waitForTransaction times out. - test.skip(isDevMode, 'Turbopack intermittently returns 404 for nested dynamic routes in dev mode'); + test.skip(isTurbopackDevMode, 'Turbopack intermittently returns 404 for nested dynamic routes in dev mode'); const serverComponentTransactionPromise = waitForTransaction('nextjs-16', transactionEvent => { return ( @@ -79,6 +77,8 @@ test('Will create a transaction with spans for every server component and metada test('Will create a transaction with spans for every server component and metadata generation functions when visiting a dynamic page', async ({ page, }) => { + test.skip(isTurbopackDevMode, 'Turbopack intermittently returns 404 for dynamic routes in dev mode'); + const serverTransactionEventPromise = waitForTransaction('nextjs-16', async transactionEvent => { return transactionEvent?.transaction === 'GET /nested-layout/[dynamic]'; });