fix(node-core): Read __SENTRY_SERVER_MODULES__ lazily so Turbopack injection is honored#21339
Open
sergical wants to merge 3 commits into
Open
fix(node-core): Read __SENTRY_SERVER_MODULES__ lazily so Turbopack injection is honored#21339sergical wants to merge 3 commits into
__SENTRY_SERVER_MODULES__ lazily so Turbopack injection is honored#21339sergical wants to merge 3 commits into
Conversation
…jection is honored `modulesIntegration` captured `__SENTRY_SERVER_MODULES__` into a module-level `const` at evaluation time. That works for webpack (DefinePlugin replaces the token with a literal at build time) but not for Turbopack: the value-injection loader assigns `globalThis.__SENTRY_SERVER_MODULES__` at runtime, and the instrumentation file's ESM imports are hoisted above that assignment — so this module evaluates before the global is set and the capture is always empty. As a result, on Next.js 16 / Turbopack production builds (e.g. Vercel) every module-detection-based auto integration silently never activates (vercelAI, openAI, anthropic, googleGenAI, langChain, langGraph), and `event.modules` is missing server dependencies. Read the value lazily instead: prefer the build-time-replaced token (webpack), then fall back to `GLOBAL_OBJ.__SENTRY_SERVER_MODULES__` (Turbopack). Adds a regression test that fails when the value is captured at module-eval time. Ref: #19147 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the root cause behind #19147. On Next.js 16 / Turbopack production builds (e.g. Vercel),
modulesIntegrationreturns no injected modules, which silently disables every module-detection-based auto integration —vercelAIIntegration,openAIIntegration,anthropicAIIntegration,googleGenAIIntegration,langChainIntegration,langGraphIntegration— and leavesevent.modulesmissing server dependencies. The result users see: rawai.*spans (op: default) instead ofgen_ai.*.Root cause
packages/node-core/src/integrations/modules.tscaptured the injected value into a module-levelconstat evaluation time:The two bundlers inject
__SENTRY_SERVER_MODULES__differently:DefinePlugin→ available the moment this module evaluates. ✅globalThis.__SENTRY_SERVER_MODULES__at runtime, via a value-injection loader oninstrumentation.*.The catch: the
instrumentation.*file's ESMimports are hoisted above the injected assignment. Verified in a real Turbopack build (.next/server/chunks/[root-of-the-server]__*.js):So
@sentry/node-core/modulesevaluates before the global is assigned, and theconstis frozen as{}. The other two sources incollectModules()also come up empty on a bundled server (no full-dependencypackage.jsonatprocess.cwd();aiis bundled so it's not inrequire.cache, and the server is ESM not CJS). Net:getModules().aiisundefined→shouldForceIntegrationreturnsfalse→addVercelAiProcessorsnever attaches.Why #19231 didn't catch it
#19231 was unit-tested at the config-generation layer (asserting the value-injection rule is emitted). The
nextjs-16AI E2E that assertsgen_ai.*spans passes for the wrong reason — it runsnext startlocally, wheregetModulesFromPackageJson()readsprocess.cwd()/package.json(present, listsai) and masks the brokenSERVER_MODULESpath. On Vercel that fallback is empty, so detection fails.Fix
Read the value lazily (per call) instead of capturing it at module-eval time, and support both injection styles:
By the time
getModules()is first called (during integrationafterAllSetup, i.e. afterregister()→Sentry.init()), the instrumentation module body has fully executed and the global is set. webpack is unaffected (token still replaced).Regression test
packages/node-core/test/integrations/modules.test.tsre-imports the module with no global set (mirroring Turbopack), then assignsglobalThis.__SENTRY_SERVER_MODULES__after import and assertsgetModules()reflects it. This fails on the previous code and passes with the fix.Blast radius
Low. webpack path unchanged; Turbopack now honored;
event.modulesrestored on Turbopack. Re-enables all module-detection-based auto integrations on Next.js 16 without requiringvercelAIIntegration({ force: true }).Follow-up (separate)
The existing
nextjs-16AI E2E should be hardened so it can't pass via theprocess.cwd()package.json fallback — e.g. a--turbopackbuild variant run from a working directory whosepackage.jsondoes not list the AI SDK, assertinggen_ai.*spans still appear. Happy to do this in a follow-up.🤖 Generated with Claude Code