Skip to content

Runtime injection does not instrument modules loaded by tsx on Node 24.13+ #24787

Description

@JPeer264

Follow up to #24343

From Node 24.13 / 25.1, registerDiagnosticsChannelInjection() in @sentry/server-runtime-injection registers Module.registerHooks({ resolve, load }) and, unlike the Module.register path for older Node versions, does not patch Module.prototype._compile. Runners that compile CommonJS themselves (tsx, ts-node) take over require, so the files they load never reach the sync load hook and stay uninstrumented.

On Node 24.21, a script that calls Sentry.init() and then requires express and mysql records __SENTRY_ORCHESTRION__.runtime as ["express","express"] under plain node, and [] under tsx. Every user who runs their app with tsx or ts-node on Node 24.13+ loses channel-based spans today, for example the express route name on http.server segments.

In the tsx-express E2E app on Node 24.21, 8 of 10 tests failed: error events without the route segment, API route spans, MCP handler spans and all four tRPC tests.

A first fix in #24343 (later removed from that PR) added the _compile patch on the registerHooks path. On its own it transforms every file twice when a plain require goes through both the sync hook and _compile, which records each module twice (runtime=["dataloader","dataloader"]) and broke the esbuild orchestrion suite and the Deno @sentry/deno/import tests. Skipping _compile for the files the sync hook already transformed fixed that, and the unit, esbuild and Deno suites passed with it.

When this is fixed, remove the volta.node pin (20.19.5) from the tsx-express E2E app, which #24343 added so its E2E tests keep running on Node 20.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions