Skip to content

nextjs: Next 16 request yields a route-less http.server segment named only by method, plus the route-named one #25370

Open

Description

@rhbra

Environment

  • @sentry/nextjs 11.7.0 (default span streaming), @sentry/node 11.7.0
  • 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.

Activity

  1. linear-code commented on Oct 14, 2026

    @linear-code
  2. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Oct 14, 2026
  3. self-assigned this
    on Oct 14, 2026
  4. Lms24 commented on Oct 14, 2026

    @Lms24
    Member

    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.

  5. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions