Skip to content

TanStack Start on Nitro: first request per server instance has no http.server span without --import #25970

Open

Description

@ryanhiizy

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/tanstackstart-react

SDK Version

11.10.0

Framework Version

@tanstack/react-start 1.168.60, nitro 3.0.260903-beta

Reproduction Example/SDK Setup

On hosts where node --import isn't available, such as Vercel, #19458 recommends importing the instrumentation first in server.ts:

// src/server.ts
import './instrument.server';
import { wrapFetchWithSentry } from '@sentry/tanstackstart-react';
import handler, { createServerEntry } from '@tanstack/react-start/server-entry';

export default createServerEntry(
  wrapFetchWithSentry({
    fetch(request: Request) {
      return handler.fetch(request);
    },
  }),
);
// src/instrument.server.ts
import * as Sentry from '@sentry/tanstackstart-react';

Sentry.init({ dsn: '...', tracesSampleRate: 1, debug: true });
console.log('[sentry] init');

The app is your tanstackstart-react e2e test app, cut down to __root and index, using the nitro() and sentryTanstackStart() Vite plugins.

Steps to Reproduce

  1. Run vite build.
  2. Run node .output/server/index.mjs, without --import.
  3. Request / twice.

Expected Result

Both requests produce an http.server root span.

Actual Result

[sentry] init isn't printed at startup. It's printed when the first request arrives, so the HTTP instrumentation misses that request:

Listening on: http://localhost:3107/
# first request
[sentry] init
[Tracing] Starting sampled root span
  op: middleware
  name: globalRequestMiddleware
Sending span envelope for trace e4ef... with 1 spans
# second request
Http.Server Handling incoming request
[Tracing] Starting sampled root span
  op: http.server
  name: GET
[Tracing] Starting sampled span
  op: middleware
  name: globalRequestMiddleware
Sending span envelope for trace aa6e... with 2 spans

Additional Context

Nitro loads the server entry lazily, so server.ts first runs inside the first request:

// .output/server/index.mjs
var _lazy = defineLazyEventHandler(() => import("./_chunks/ssr-renderer.mjs"));

On serverless hosts this repeats for every new instance, so the requests with no trace are the cold starts. We see about 2,000 a day on a Vercel staging deployment (measured on SDK 11.9.0).

We tried calling Sentry.init from a Nitro plugin, which runs at startup. The plugin bundled a second copy of the SDK that never received the route names, so route naming broke and we reverted it. A supported way to initialise from a Nitro plugin, or to have the Vite plugin do it, would fix this.

This was written by Opus 5.5.

Activity

  1. linear-code commented on Oct 31, 2026

    @linear-code
  2. self-assigned this
    on Nov 4, 2026
  3. added a commit that references this issue on Nov 4, 2026
    6cde267
  4. chargome commented on Nov 5, 2026

    @chargome
    Member

    Thanks for reaching out, we'll look into it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions