Skip to content

createSentryServerInstrumentation() return type is not assignable to react-router's ServerInstrumentation (mirrored types drifted since react-router 8.1.0) #23265

Description

@lasseklovstad

Which SDK are you using?

@sentry/react-router

SDK Version

10.69.0 — also verified still present in the 10.70.0 tag's source (packages/react-router/src/common/types.ts is byte-identical)

Framework Version

react-router 8.3.0 (regression introduced in 8.1.0, see below)

Reproduction Example/SDK Setup

On any React Router 8.1+ framework-mode app with strict TypeScript, following the instrumentation docs in entry.server.tsx:

import * as Sentry from "@sentry/react-router";
import type { ServerInstrumentation } from "react-router";

export const instrumentations: ServerInstrumentation[] = [
  Sentry.createSentryServerInstrumentation(),
];

No Sentry.init specifics are relevant — this is a compile-time-only failure and reproduces regardless of runtime config.

Steps to Reproduce

  1. Install react-router@>=8.1.0 and @sentry/react-router@10.70.0.
  2. Export instrumentations from entry.server.tsx, annotated with React Router's own ServerInstrumentation type (as its instrumentation guide shows).
  3. Run tsc --noEmit.

Expected Result

createSentryServerInstrumentation() is assignable to react-router's ServerInstrumentation, so the documented setup typechecks.

Actual Result

error TS2322: Type '@sentry/react-router/build/types/common/types".ServerInstrumentation'
  is not assignable to type 'react-router/dist/production/lib/router/instrumentation".ServerInstrumentation'.
  Types of property 'handler' are incompatible.
    Type '((handler: InstrumentableRequestHandler) => void) | undefined' is not assignable to type 'InstrumentRequestHandlerFunction | undefined'.
      Type '(handler: InstrumentableRequestHandler) => void' is not assignable to type 'InstrumentRequestHandlerFunction'.
        Types of parameters 'handler' and 'handler' are incompatible.
          Type 'InstrumentableRequestHandler' is not assignable to type '@sentry/react-router/build/types/common/types".InstrumentableRequestHandler'.

Additional Context

Root cause: the mirrored type file has drifted

packages/react-router/src/common/types.ts is a hand-maintained copy of React Router's instrumentation types, and carries this note:

Derived from React Router's instrumentations API. If React Router changes these types, this file must be updated.

React Router changed them and the copy wasn't re-synced:

Date Event
2026-06-15 Last update to common/types.ts (#21470, "Stabilize the instrumentation API")
2026-06-24 peerDependencies bumped for react-router 8 (#21762)
2026-06-25 react-router #15235 "Add instrumentation result metadata" merged
2026-06-29 Shipped in react-router@8.1.0

Concrete divergences (react-router 8.3.0 vs @sentry/react-router 10.70.0)

react-router @sentry/react-router
request handler result InstrumentationServerHandlerResult — adds statusCode: number and meta InstrumentationResult — neither field
navigate / fetch result InstrumentationClientRouterResult — adds meta InstrumentationResult
error in result Error unknown
handler info request ReadonlyRequest Request ← what TS reports above
handler info context Pick<RouterContextProvider, "get"> unknown
route handler info Readonly<Omit<LoaderFunctionArgs, "request" | "context"> & {...}>pattern and url required { params, pattern?, unstable_pattern?, context? }

Runtime appears unaffected

Reading createServerInstrumentation.ts at the 10.70.0 tag, the instrumentation only consumes info.request.method, info.request.url (via getPathFromRequest), info.pattern ?? info.unstable_pattern, and result.status / result.error instanceof Error. React Router 8.3.0 supplies all of those — pattern is a required field on DataFunctionArgs, and the added statusCode/meta fields are simply ignored. So this looks like a types-only problem, with spans and errors still reported correctly. Worth confirming on your side, though, since statusCode is now available and currently invisible to the SDK.

Workaround

Dropping the annotation, or a single cast, both compile:

export const instrumentations = [Sentry.createSentryServerInstrumentation()];
// or
export const instrumentations: ServerInstrumentation[] = [
  Sentry.createSentryServerInstrumentation() as ServerInstrumentation,
];

Suggested fix

Beyond re-syncing the file, the mirroring itself is the recurring failure mode — this will drift again on the next React Router change. Since react-router is already a peer dependency, importing its exported instrumentation types (ServerInstrumentation, ClientInstrumentation, InstrumentableRequestHandler, InstrumentableRoute) would make the mismatch impossible. If the copy has to stay for peer-range reasons, a type-level assignability assertion in the test suite against the mirrored shapes would at least turn the drift into a CI failure rather than a downstream compile error.

Metadata

Metadata

Assignees

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions