Skip to content

fix(node): Skip registration-only instrumentations in the runtime loader - #24240

Open
mydea wants to merge 4 commits into
developfrom
fn/fix-orchestrion-register
Open

fix(node): Skip registration-only instrumentations in the runtime loader#24240
mydea wants to merge 4 commits into
developfrom
fn/fix-orchestrion-register

Conversation

@mydea

@mydea mydea commented Sep 9, 2026

Copy link
Copy Markdown
Member

Registration-only orchestrion configs — native-channel libraries such as ai v7, ioredis, @redis/client, mysql2 and mongoose — carry the custom MODULE_REGISTRATION_TRANSFORM. That transform is wired into the bundler plugins only (orchestrion/bundler/moduleInjectedTransform.ts, via bundler/options.ts's customTransforms); the runtime loader (@sentry/server-runtime-injection's register) passes no custom transforms to initialize(). So when one of these modules loads through the runtime hook, getTransformer returns a transformer whose .transform is undefined and the loader throws TypeError: transform is not a function. The diagnostics callback treats any TypeError as a stripped/bundled transformer and emits the always-on warning:

[Sentry] `@sentry/server-runtime-injection` was bundled into your application, so <module> and any other instrumented dependency load uninstrumented. ...

…even though nothing is wrong: these libraries publish their own tracing channels and are instrumented via setupOnce() / waitForTracingChannelBinding, independently of the module-registration snippet.

This excludes registration-only configs from a new SENTRY_RUNTIME_INSTRUMENTATIONS set used by the runtime loader; the bundler keeps the full SENTRY_INSTRUMENTATIONS. Skipping them at runtime is lossless rather than a workaround: the registration snippet only fires orchestrion.module-injected, which drives the orchestrion:* subscription these native versions never publish (a no-op at runtime). The snippet earns its keep only on the bundler path (e.g. bundler-only SDKs like @sentry/cloudflare that discover a loaded module via that event); @sentry/node registers its integrations statically.

Root cause: the sentryModuleRegistration custom transform used by registration-only configs is registered in orchestrion/bundler/* but never in the runtime path, so the runtime code transformer cannot apply it.

Noticed this here: #24228

Tests:

  • server-utils unit test — SENTRY_RUNTIME_INSTRUMENTATIONS drops every registration-only config and keeps the rest, and asserts the exclusion is per-config, not per-module.
  • node-integration-test — loading a native-channel library (mysql2 ≥ 3.20) with the runtime loader active emits no transformer-unavailable warning (via ensureNoErrorOutput); it fails against the unfiltered set and passes with this change.

🤖 Generated with Claude Code

mydea and others added 4 commits September 9, 2026 12:49
Registration-only orchestrion configs (native-channel libraries — ai v7,
ioredis, @redis/client, mysql2, mongoose) carry a custom transform wired into
the bundler plugins only. The runtime loader (`@sentry/server-runtime-injection`
`register`) has no custom transforms, so transforming these modules threw
`TypeError: transform is not a function`, which the diagnostics callback
misreported as the always-on "`@sentry/server-runtime-injection` was bundled
... loads uninstrumented" warning — even though the libraries are correctly
instrumented via their native channel (`setupOnce` / `waitForTracingChannelBinding`).

Exclude registration-only configs from the runtime instrumentation set
(`SENTRY_RUNTIME_INSTRUMENTATIONS`). This is lossless: at runtime the snippet
would only trigger a no-op subscription to `orchestrion:*` channels these
versions never publish.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- server-utils unit test: `SENTRY_RUNTIME_INSTRUMENTATIONS` drops every
  registration-only config and keeps the rest in order, and documents the
  affected native-channel modules (`@redis/client`, `ai`, `ioredis`, `mongoose`,
  `mysql2`), asserting the exclusion is per-config not per-module.
- node-integration-test: with the runtime loader active, loading a native-channel
  library (`mysql2` >= 3.20) emits no "transform is not a function" /
  "server-runtime-injection was bundled" warning (`ensureNoErrorOutput`). This
  fails against the unfiltered set and passes with the fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`.toContain([...])` checks for the whole array as a single member, so it never
matched. Use `arrayContaining` so the assertion documents the known
native-channel modules without breaking when another such library is added.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 28.81 kB +0.04% +11 B 🔺
@sentry/browser - with treeshaking flags 27.12 kB +0.04% +10 B 🔺
@sentry/browser - with treeshaking flags tracing without tracing 27.01 kB +0.03% +7 B 🔺
@sentry/browser (incl. Tracing) 49.22 kB -0.01% -2 B 🔽
@sentry/browser (incl. Tracing + Span Streaming) 49.22 kB +0.02% +5 B 🔺
@sentry/browser (incl. Tracing, Profiling) 52.15 kB +0.05% +21 B 🔺
@sentry/browser (incl. Tracing, Replay) 88.76 kB -0.01% -2 B 🔽
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 77.94 kB -0.02% -10 B 🔽
@sentry/browser (incl. Tracing, Replay with Canvas) 93.44 kB +0.01% +1 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 106.38 kB +0.01% +10 B 🔺
@sentry/browser (incl. Feedback) 46.3 kB +0.02% +5 B 🔺
@sentry/browser (incl. sendFeedback) 33.87 kB +0.02% +6 B 🔺
@sentry/browser (incl. FeedbackAsync) 38.99 kB +0.04% +13 B 🔺
@sentry/browser (incl. Metrics) 29.84 kB +0.08% +23 B 🔺
@sentry/browser (incl. Logs) 30.1 kB +0.06% +18 B 🔺
@sentry/browser (incl. Metrics & Logs) 30.78 kB +0.11% +31 B 🔺
@sentry/react 30.57 kB +0.05% +14 B 🔺
@sentry/react (incl. Tracing) 51.57 kB +0.03% +12 B 🔺
@sentry/vue 36.07 kB +0.05% +17 B 🔺
@sentry/vue (incl. Tracing) 51.49 kB +0.04% +19 B 🔺
@sentry/svelte 28.85 kB +0.06% +15 B 🔺
CDN Bundle 30.56 kB +0.05% +15 B 🔺
CDN Bundle (incl. Tracing) 49.76 kB +0.06% +25 B 🔺
CDN Bundle (incl. Logs, Metrics) 32.83 kB +0.03% +9 B 🔺
CDN Bundle (incl. Tracing, Logs, Metrics) 51.7 kB -0.01% -1 B 🔽
CDN Bundle (incl. Replay, Logs, Metrics) 73.48 kB -0.01% -4 B 🔽
CDN Bundle (incl. Tracing, Replay) 87.28 kB -0.01% -8 B 🔽
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 89.2 kB +0.03% +20 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 93.21 kB -0.01% -3 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 95.22 kB +0.01% +8 B 🔺
CDN Bundle - uncompressed 90.47 kB +0.01% +8 B 🔺
CDN Bundle (incl. Tracing) - uncompressed 148.17 kB -0.01% -1 B 🔽
CDN Bundle (incl. Logs, Metrics) - uncompressed 97.04 kB +0.01% +8 B 🔺
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 154.13 kB -0.01% -1 B 🔽
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 226.3 kB +0.01% +8 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed 267.76 kB -0.01% -1 B 🔽
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 273.71 kB -0.01% -1 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 281.46 kB -0.01% -1 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 287.4 kB -0.01% -1 B 🔽
@sentry/nextjs (client) 54.03 kB +0.06% +31 B 🔺
@sentry/sveltekit (client) 49.68 kB +0.06% +26 B 🔺
@sentry/core/server 36.99 kB - -
@sentry/core/browser 13.55 kB - -
@sentry/node 127.89 kB +0.08% +98 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 81.64 kB +0.04% +25 B 🔺
@sentry/node - without tracing 88.78 kB +0.08% +70 B 🔺
@sentry/node - without channel injection 107.11 kB +0.08% +80 B 🔺
@sentry/aws-serverless 97.16 kB +0.08% +68 B 🔺
@sentry/cloudflare (withSentry) - minified 201.98 kB - -
@sentry/cloudflare (withSentry) 502.68 kB - -

View base workflow run

@mydea
mydea marked this pull request as ready for review September 9, 2026 11:41
@mydea
mydea requested review from a team as code owners September 9, 2026 11:41
@mydea
mydea requested review from JPeer264 and isaacs and removed request for a team September 9, 2026 11:41
mydea added a commit that referenced this pull request Sep 10, 2026
…he runtime warning (#24242)

The runtime loader emitted the always-on `[Sentry]
@sentry/server-runtime-injection was bundled ... loads uninstrumented`
warning for **any** `TypeError` thrown while transforming a module. That
equated "a transform threw a TypeError" with "the transformer was
stripped by a bundler", so an unrelated per-module failure was reported
as a bundling problem — pointing users at externalizing the package,
which can itself break other setups.

This makes the warning honest and self-diagnosing:

- **Include the underlying error** in the message, so the reader can see
the actual cause instead of a hardcoded diagnosis they can't verify
(`debug: true` still logs the full error/stack).
- **Only claim "bundled" for the transform pipeline itself going
missing** — `parse`/`generate is not a function`, the fingerprint of a
bundler tree-shaking the vendored meriyah/astring parser, which fails
every module the same way — guarded by nothing having been instrumented
yet (a transformer that already instrumented something is provably not
stripped). Any other transform `TypeError` (e.g. `transform is not a
function`) now gets a scoped `Could not instrument <module> (...)`
message that points at reporting it, not changing the build.

_Root cause of the misclassification_: the callback branched on `error
instanceof TypeError` alone. The systemic (stripped-transformer) case
has a distinct signature (`parse`/`generate is not a function`), so
classifying on that — with the success marker as a secondary guard —
separates it from isolated per-module failures with a reasonable success
rate.

A message-based heuristic is the pragmatic fix here; a follow-up
upstream change to the transformer (`nodejs/orchestrion-js`) to throw
typed/coded errors would let this classification be exact rather than
string-matched.

Related to #24240, which removes the specific registration-only cause
that surfaced this; this hardens the warning for any remaining/future
cause.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant