From 3431fe5d8534ab723da7cc0bb2bc31c263d9c338 Mon Sep 17 00:00:00 2001 From: Abdelrahman Awad Date: Wed, 10 Dec 2025 12:20:07 +0200 Subject: [PATCH 1/4] feat(nextjs): Remove tracing from middelware wrappers --- .../src/common/wrapMiddlewareWithSentry.ts | 42 ++++++------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts b/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts index 985354543a0d..54803049ec6b 100644 --- a/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts +++ b/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts @@ -1,14 +1,10 @@ -import type { TransactionSource } from '@sentry/core'; import { captureException, getActiveSpan, getCurrentScope, getRootSpan, handleCallbackErrors, - SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, - SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, setCapturedScopesOnSpan, - startSpan, winterCGRequestToRequestData, withIsolationScope, } from '@sentry/core'; @@ -31,6 +27,7 @@ export function wrapMiddlewareWithSentry( ? (globalThis as Record)._sentryRewritesTunnelPath : undefined; + // TODO: This can never work with Turbopack, need to remove it for consistency between builds. if (tunnelRoute && typeof tunnelRoute === 'string') { const req: unknown = args[0]; // Check if the current request matches the tunnel route @@ -51,23 +48,21 @@ export function wrapMiddlewareWithSentry( } } } + // TODO: We still should add central isolation scope creation for when our build-time instrumentation does not work anymore with turbopack. return withIsolationScope(isolationScope => { const req: unknown = args[0]; const currentScope = getCurrentScope(); let spanName: string; - let spanSource: TransactionSource; if (req instanceof Request) { isolationScope.setSDKProcessingMetadata({ normalizedRequest: winterCGRequestToRequestData(req), }); spanName = `middleware ${req.method}`; - spanSource = 'url'; } else { spanName = 'middleware'; - spanSource = 'component'; } currentScope.setTransactionName(spanName); @@ -78,7 +73,6 @@ export function wrapMiddlewareWithSentry( // If there is an active span, it likely means that the automatic Next.js OTEL instrumentation worked and we can // rely on that for parameterization. spanName = 'middleware'; - spanSource = 'component'; const rootSpan = getRootSpan(activeSpan); if (rootSpan) { @@ -86,30 +80,18 @@ export function wrapMiddlewareWithSentry( } } - return startSpan( - { - name: spanName, - op: 'http.server.middleware', - attributes: { - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: spanSource, - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs.wrap_middleware', - }, + return handleCallbackErrors( + () => wrappingTarget.apply(thisArg, args), + error => { + captureException(error, { + mechanism: { + type: 'auto.function.nextjs.wrap_middleware', + handled: false, + }, + }); }, () => { - return handleCallbackErrors( - () => wrappingTarget.apply(thisArg, args), - error => { - captureException(error, { - mechanism: { - type: 'auto.function.nextjs.wrap_middleware', - handled: false, - }, - }); - }, - () => { - waitUntil(flushSafelyWithTimeout()); - }, - ); + waitUntil(flushSafelyWithTimeout()); }, ); }); From f687f590b67871e732c4910da59a620a9bd202ad Mon Sep 17 00:00:00 2001 From: Abdelrahman Awad Date: Wed, 10 Dec 2025 12:35:14 +0200 Subject: [PATCH 2/4] feat: remove all span ops from middleware wrapper --- .../src/common/wrapMiddlewareWithSentry.ts | 69 ++++--------------- 1 file changed, 14 insertions(+), 55 deletions(-) diff --git a/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts b/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts index 54803049ec6b..f02e664fc0f6 100644 --- a/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts +++ b/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts @@ -1,13 +1,4 @@ -import { - captureException, - getActiveSpan, - getCurrentScope, - getRootSpan, - handleCallbackErrors, - setCapturedScopesOnSpan, - winterCGRequestToRequestData, - withIsolationScope, -} from '@sentry/core'; +import { captureException, handleCallbackErrors } from '@sentry/core'; import { flushSafelyWithTimeout, waitUntil } from '../common/utils/responseEnd'; import type { EdgeRouteHandler } from '../edge/types'; @@ -49,52 +40,20 @@ export function wrapMiddlewareWithSentry( } } - // TODO: We still should add central isolation scope creation for when our build-time instrumentation does not work anymore with turbopack. - return withIsolationScope(isolationScope => { - const req: unknown = args[0]; - const currentScope = getCurrentScope(); - - let spanName: string; - - if (req instanceof Request) { - isolationScope.setSDKProcessingMetadata({ - normalizedRequest: winterCGRequestToRequestData(req), + return handleCallbackErrors( + () => wrappingTarget.apply(thisArg, args), + error => { + captureException(error, { + mechanism: { + type: 'auto.function.nextjs.wrap_middleware', + handled: false, + }, }); - spanName = `middleware ${req.method}`; - } else { - spanName = 'middleware'; - } - - currentScope.setTransactionName(spanName); - - const activeSpan = getActiveSpan(); - - if (activeSpan) { - // If there is an active span, it likely means that the automatic Next.js OTEL instrumentation worked and we can - // rely on that for parameterization. - spanName = 'middleware'; - - const rootSpan = getRootSpan(activeSpan); - if (rootSpan) { - setCapturedScopesOnSpan(rootSpan, currentScope, isolationScope); - } - } - - return handleCallbackErrors( - () => wrappingTarget.apply(thisArg, args), - error => { - captureException(error, { - mechanism: { - type: 'auto.function.nextjs.wrap_middleware', - handled: false, - }, - }); - }, - () => { - waitUntil(flushSafelyWithTimeout()); - }, - ); - }); + }, + () => { + waitUntil(flushSafelyWithTimeout()); + }, + ); }, }); } From 3dd5b3a5cce44e0188e80049c748032477d1640b Mon Sep 17 00:00:00 2001 From: Abdelrahman Awad Date: Wed, 10 Dec 2025 13:04:01 +0200 Subject: [PATCH 3/4] fix: still set the trasnaction name --- packages/nextjs/src/common/wrapMiddlewareWithSentry.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts b/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts index f02e664fc0f6..b929dbcc61a5 100644 --- a/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts +++ b/packages/nextjs/src/common/wrapMiddlewareWithSentry.ts @@ -1,4 +1,4 @@ -import { captureException, handleCallbackErrors } from '@sentry/core'; +import { captureException, getCurrentScope, handleCallbackErrors } from '@sentry/core'; import { flushSafelyWithTimeout, waitUntil } from '../common/utils/responseEnd'; import type { EdgeRouteHandler } from '../edge/types'; @@ -40,6 +40,10 @@ export function wrapMiddlewareWithSentry( } } + const req: unknown = args[0]; + const spanName = req instanceof Request ? `middleware ${req.method}` : 'middleware'; + getCurrentScope().setTransactionName(spanName); + return handleCallbackErrors( () => wrappingTarget.apply(thisArg, args), error => { From efc196f5c51143d1b40fa7df738ba67c0a56a331 Mon Sep 17 00:00:00 2001 From: Abdelrahman Awad Date: Wed, 10 Dec 2025 14:00:43 +0200 Subject: [PATCH 4/4] tests: skip broken tests on nextjs 13 --- .../nextjs-pages-dir/tests/middleware.test.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/middleware.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/middleware.test.ts index 03539a781ec1..ffae17f6441c 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/middleware.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/middleware.test.ts @@ -1,7 +1,15 @@ import { expect, test } from '@playwright/test'; import { waitForError, waitForTransaction } from '@sentry-internal/test-utils'; +const packageJson = require('../package.json'); +const nextjsVersion = packageJson.dependencies.next; +const nextjsMajor = Number(nextjsVersion.split('.')[0]); + test('Should create a transaction for middleware', async ({ request }) => { + test.skip( + nextjsMajor === 13, + 'Middleware transactions are not created in Next.js 13 after dropping tracing from middleware', + ); const middlewareTransactionPromise = waitForTransaction('nextjs-pages-dir', async transactionEvent => { return transactionEvent?.transaction === 'middleware GET'; }); @@ -22,6 +30,10 @@ test('Should create a transaction for middleware', async ({ request }) => { }); test('Faulty middlewares', async ({ request }) => { + test.skip( + nextjsMajor === 13, + 'Middleware transactions are not created in Next.js 13 after dropping tracing from middleware', + ); const middlewareTransactionPromise = waitForTransaction('nextjs-pages-dir', async transactionEvent => { return transactionEvent?.transaction === 'middleware GET'; }); @@ -53,6 +65,10 @@ test('Faulty middlewares', async ({ request }) => { }); test('Should trace outgoing fetch requests inside middleware and create breadcrumbs for it', async ({ request }) => { + test.skip( + nextjsMajor === 13, + 'Middleware transactions are not created in Next.js 13 after dropping tracing from middleware', + ); const middlewareTransactionPromise = waitForTransaction('nextjs-pages-dir', async transactionEvent => { return ( transactionEvent?.transaction === 'middleware GET' &&