You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
nextjs: Next 16 request yields a route-less http.server segment named only by method, plus the route-named one #25370
next 16.4.0, App Router, proxy.ts present, output: 'standalone', next build with Turbopack, run with node server.js
Sentry.init in instrumentation.ts with tracesSampleRate: 1, no ignoreSpans, no custom sampler
What happens
Each request produces three separate segment spans in the same trace, none with a parent:
name
sentry.op
http.route
middleware GET
middleware
middleware GET
GET
http.server
none
GET /login
http.server
/login
Captured by pointing the DSN at a local HTTP sink (one request each to /login and /api/users/me). For /login, the bare GET starts within a millisecond of middleware GET and ends when it ends; GET /login starts when the bare GET ends. The bare GET has url.path set but no http.route or next.route, and enhanceHandleRequestRootSpan only names a span from next.route/http.route, so it keeps the method as its name. Every route's bare GET looks the same.
Why it matters
http.server is counted twice per request, so transaction counts, failure rates and p95 over span.op:http.server are skewed.
When the named segment is dropped (for example by Sentry's "Filter out health check transactions" inbound filter, which matches GET /api/health), the bare GET for that request is still ingested, so a filtered route still shows up as GET.
What I tried
ignoreSpans: [{ name: /^(GET|POST)$/, op: 'http.server' }] drops a span created with that name and op in a unit test (startSpan), but removes nothing from the real Next server. I did not find out why. My guess is that the name or op is set after the filter runs, but I have not confirmed that.
Not tested
I did not run the same app without proxy.ts, so "the bare root is the proxy phase" is inferred from timing and the middleware GET sibling, not confirmed.
Expected
One http.server segment per request, named by route, with the proxy/middleware work as a child or as a clearly separate segment that is not also op http.server.
Hey @rhbra thanks for reporting! I'm going to look into this. My current thinking is we should avoid creating the GET span in the first place and leave the two middleware GET and GET /login spans be separate segments. This is probably the thing closest to how NextJS intends to have its traces look like (our SDK mostly picks up the spans emitted from NextJS). Might be a bit tricky to implement but I'm working on this right now.
Activity
linear-code commentedon Oct 14, 2026
JS-3937
Lms24 commentedon Oct 14, 2026
Hey @rhbra thanks for reporting! I'm going to look into this. My current thinking is we should avoid creating the
GETspan in the first place and leave the twomiddleware GETandGET /loginspans be separate segments. This is probably the thing closest to how NextJS intends to have its traces look like (our SDK mostly picks up the spans emitted from NextJS). Might be a bit tricky to implement but I'm working on this right now.