Is there an existing issue for this?
How do you use Sentry?
Sentry Saas (sentry.io)
Which SDK are you using?
@sentry/nextjs
SDK Version
10.38.0
Framework Version
18.17.1
Link to Sentry event
No response
Reproduction Example/SDK Setup
No response
Steps to Reproduce
For all requests traced in our Next.js application, we see duplicate root spans. The application seems to start two root spans. One of the spans becomes the "current" span, which child spans attach to. The other span is empty.
We are primarily doing distributed tracing, so the spans in this application starts with sentry request headers.
This is our configuration
- Trace requests in a Next.js application
next.config.js
const nextConfig = {
experimental: {
instrumentationHook: true,
},
typescript: {
ignoreBuildErrors: true,
},
eslint: {
dirs: ['components', 'pages', 'modules', 'contexts', 'hooks', 'lib'],
},
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: ['@svgr/webpack'],
})
return config
},
}
module.exports = nextConfig
const { withSentryConfig } = require('@sentry/nextjs')
module.exports = withSentryConfig(module.exports, {
silent: true,
ignore: [
'**/*.css',
'**/*.scss',
'**/*.less',
'**/*.png',
'**/*.jpg',
'**/*.jpeg',
'**/*.gif',
'**/*.svg',
'**/public/**',
],
include: '.next'
})
** instrumentation-server.ts **
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: {dsn},
// Server runtime sampling
// parentSampled is automatically populated from sentry-trace header sent by browser or edge
// When browser/edge samples a trace, they send: sentry-trace: <trace-id>-<span-id>-1
// Next.js Sentry SDK extracts this header and sets parentSampled=true if sampled=1
tracesSampler: ({ attributes, parentSampled }) => {
// If parent (browser or edge) sampled the trace, always sample to keep trace complete
// This ensures browser → edge → server traces remain connected
if (parentSampled === true) {
return 1.0
}
// Sample 0.1% of other spans (regular application traffic)
// Note: Uptime bot detection happens at edge (entry point), so we don't check here
return 0.001
},
environment: process.env.ENVIRONMENT || 'production',
// Add tags to differentiate server-side traces
beforeSendTransaction(event) {
// Add runtime tag to identify server-side transactions
if (event.tags) {
event.tags.runtime = 'server'
} else {
event.tags = { runtime: 'server' }
}
// Modify OP for root transaction to indicate server runtime
if (event.contexts?.trace?.op) {
event.contexts.trace.op = `server.${event.contexts.trace.op}`
}
// Modify OP for each span to indicate server-side
event.spans =
event.spans?.map((span) => {
span.op = `server.${span.op}`
return span
}) || []
return event
},
// Configure trace propagation targets for distributed tracing
// This enables sentry-trace headers to be sent to these domains
tracePropagationTargets: [
/^(https?:\/\/)?(content|search|api)\.(test\.)?example\.[a-z]+$/,
process.env.DRUPAL_BASE_URL
? new RegExp(`^${process.env.DRUPAL_BASE_URL.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`)
: undefined,
].filter((target): target is RegExp => target !== undefined),
})
Expected Result
A single root span for traced requests, with child spans attaching to the single root span.
Actual Result
Duplicate root spans for traced requests. The two root spans have the same name, one is empty and one has child spans.
- The empty span has
span_type set to BaseServer.handleRequest
- The span with child spans has
origin set to auto.http.nextjs
Additional Context
This is a distributed trace, and the trace starts because the request comes with sentry trace headers.
We've tried setting autoInstrumentMiddleware: false as well as autoInstrumentServerFunctions: false. That had no effect.
Priority
React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it.
Is there an existing issue for this?
How do you use Sentry?
Sentry Saas (sentry.io)
Which SDK are you using?
@sentry/nextjs
SDK Version
10.38.0
Framework Version
18.17.1
Link to Sentry event
No response
Reproduction Example/SDK Setup
No response
Steps to Reproduce
For all requests traced in our Next.js application, we see duplicate root spans. The application seems to start two root spans. One of the spans becomes the "current" span, which child spans attach to. The other span is empty.
We are primarily doing distributed tracing, so the spans in this application starts with sentry request headers.
This is our configuration
next.config.js
** instrumentation-server.ts **
Expected Result
A single root span for traced requests, with child spans attaching to the single root span.
Actual Result
Duplicate root spans for traced requests. The two root spans have the same name, one is empty and one has child spans.
span_typeset toBaseServer.handleRequestoriginset toauto.http.nextjsAdditional Context
This is a distributed trace, and the trace starts because the request comes with sentry trace headers.
We've tried setting
autoInstrumentMiddleware: falseas well asautoInstrumentServerFunctions: false. That had no effect.Priority
React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding
+1orme too, to help us triage it.