Skip to content

wrapFetchWithSentry's injected trace meta tags break React 19 document hydration (error #418 on every SSR page) #21915

Description

@zenato

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

10.63.0

Framework Version

React 19.2.4, @tanstack/react-start 1.168.26 (Vite 8 + Nitro)

Link to Sentry event

No response

Reproduction Example/SDK Setup

Standard TanStack Start setup per the SDK docs — the relevant part is the server entry:

// src/server.tsimport'../instrument.server.mjs'import{wrapFetchWithSentry}from'@sentry/tanstackstart-react'importhandler,{createServerEntry}from'@tanstack/react-start/server-entry'exportdefaultcreateServerEntry(wrapFetchWithSentry({fetch(request: Request){returnhandler.fetch(request)},}),)
// instrument.server.mjsimport*asSentryfrom'@sentry/tanstackstart-react'Sentry.init({dsn: process.env.VITE_SENTRY_DSN,tracesSampleRate: 0,})

Client entry is the TanStack Start default (whole-document hydration):

// src/client.tsxhydrateRoot(document,<StrictMode><StartClient/></StrictMode>,)

Steps to Reproduce

  1. Create a TanStack Start (React 19) app and set up @sentry/tanstackstart-react >= 10.55.0 per the docs, including wrapFetchWithSentry in the server entry.
  2. Make a production build and run it with a server-side DSN configured (any syntactically valid DSN reproduces it — the SDK just needs to be enabled).
  3. Open any SSR page with the browser console open.

What happens: wrapFetchWithSentryinjectMetaTagsInResponse inserts getTraceMetaTags() right after <head>. getTraceMetaTags() joins the two meta tags with '\n' (packages/core/src/utils/meta.ts), so the served HTML is:

<head><metaname="sentry-trace" content="..."/><metaname="baggage" content="..."/><metacharSet="utf-8"/>...

That newline becomes a whitespace text node inside <head>. React 19's whole-document hydration tolerates unexpected elements in <head>/<body>, but not unexpected text nodes — hydration fails with error #418 and the entire document is re-rendered on the client.

I isolated this on a production deployment by editing the served HTML and re-loading it in place (document.open()/write()/close()), same environment for all variants:

served HTML variantresult
original (both metas + \n between them)#418 on every load
both meta tags removedno error
metas kept, only the \n between them removedno error
metas removed entirely, a bare \n inserted after <head>#418

So the text node is both necessary and sufficient; the meta elements themselves are fine. Not reproducible in dev (SDK disabled → no injection), which is presumably why this hasn't been reported — it only shows in deployed apps.

Introduced with the meta tag injection in #21144 (10.55.0). Still present in 10.63.0. Possibly the same phenomenon as the "benign React #418" mentioned in passing in #21770.

Suggested fix: join the tags without the newline in getTraceMetaTags() (or inject without whitespace in addMetaTagToHead).

Expected Result

The injected trace meta tags don't interfere with React hydration: no hydration errors, and the server-rendered DOM is preserved.

Actual Result

Every SSR page load logs:

Uncaught Error: Minified React error #418; visit https://react.dev/errors/418?args[]=HTML&args[]= ...

("Hydration failed because the server rendered HTML didn't match the client.")

React recovers by re-rendering the whole document on the client, so the page looks fine, but:

  • SSR benefits are lost on every page load (full client re-render), with possible flicker and lost pre-hydration input/focus.
  • The recovery re-render rebuilds <head> and wipes the injectedsentry-trace/baggagemeta tags, so the distributed-tracing linkage this feature exists to provide is lost as well.
  • The constant #418 noise masks real hydration bugs.

Additional Context

No response

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.

Activity

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