You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Importing anything from @sentry/cloudflare/nodejs_compat inside a real workerd isolate kills the runtime with a bare SIGSEGV — no JS error, no stack trace, nothing catchable.
(the CJS build does the same via require('@sentry/node'))
@sentry/node cannot be loaded in workerd. Because it is a static re-export from the barrel, any consumer of that entry drags the whole Node SDK into the isolate, regardless of which binding they actually asked for.
This does not affect deployed Workers, because esbuild tree-shakes the unused re-export out of the bundle. It breaks contexts that load modules unbundled, most notably @cloudflare/vitest-pool-workers — so the code ships fine and then cannot be tested.
Reproduction
Minimal standalone project — four dev-dependencies, five files, inlined in full below. Happy to push it to a repo if that's easier to work with.
import{it,expect}from'vitest';import{vercelAIIntegration}from'@sentry/cloudflare/nodejs_compat';it('imports the nodejs_compat entry',()=>{expect(typeofvercelAIIntegration).toBe('function');});
npx vitest run →
*** Received signal #11: Segmentation fault: 11
stack: .../node_modules/@cloudflare/workerd-linux-64/bin/workerd@25674af ...
Error: [vitest-pool]: Worker cloudflare-pool emitted error.
Caused by: Error: Worker exited unexpectedly
Test Files (1)
Tests no tests
Expected vs actual
Expected: the entry point imports, or fails with a catchable JS error naming the unsupported module. Actual: the workerd process dies with SIGSEGV. In a multi-file test run this silently drops the affected file — the reporter prints Test Files 4 passed (5) and a non-zero exit, with no indication of which file or why.
Narrowing
Each of these was run in isolation:
Import
Result
import { vercelAIIntegration } from '@sentry/cloudflare' (root entry)
✅ passes
import { vercelAIIntegration } from '@sentry/cloudflare/nodejs_compat'
💥 SIGSEGV
import { prismaIntegration } from '@sentry/node'
💥 SIGSEGV
deep path .../build/esm/nodejs_compat/integrations/tracing/vercelai.js
✅ passes
So the AI integration itself — including its @sentry/server-utilsai:telemetry subscriber — is perfectly workerd-safe. Only the@sentry/nodere-export in the barrel is fatal.
Why this is hard to work around
Using the root entry instead is not equivalent. build/esm/integrations/tracing/vercelai.js imports only from @sentry/core, whereas the nodejs_compat variant composes it with vercelAiIntegration from @sentry/server-utils:
constinner=vercelAiIntegration(options);// the node:diagnostics_channel 'ai:telemetry' subscriberconstinstrumentation=vercelAIIntegration$1(options);// the ai.* -> gen_ai.* span processorreturn{ ...inner, ...instrumentation};
Only that composed version subscribes to ai:telemetry. With AI SDK v7 (which no longer emits OTel spans itself) the root entry produces no AI spans at all — so anyone wanting AI monitoring on Cloudflare must use nodejs_compat, which is exactly the entry that segfaults.
The deep path works but is not a supported subpath: exports only declares ., ./request and ./nodejs_compat, so there is no public way to reach the integration without the barrel.
Suggested fixes
Any one of these would resolve it:
Don't statically re-export@sentry/nodefrom a workerd entry point. Load prismaIntegration lazily inside the integration factory, so merely importing the barrel doesn't pull in the Node SDK.
Expose the AI integration on its own export subpath (e.g. @sentry/cloudflare/nodejs_compat/vercelai) so consumers can bypass the barrel.
(1) or (2) seem cleanest, since they also shrink what every nodejs_compat consumer bundles.
This looks like the same class of bug as #20038 (workerd/worker export conditions resolving to @sentry/node, breaking Cloudflare Workers).
Workaround
For anyone else hitting this — alias @sentry/node to a stub in the workers-pool vitest config. This makes the test module graph match what esbuild produces for production, where @sentry/node is absent anyway:
Package
@sentry/cloudflare(10.66.0)Summary
Importing anything from
@sentry/cloudflare/nodejs_compatinside a realworkerdisolate kills the runtime with a bare SIGSEGV — no JS error, no stack trace, nothing catchable.The cause is line 1 of that entry point:
(the CJS build does the same via
require('@sentry/node'))@sentry/nodecannot be loaded inworkerd. Because it is a static re-export from the barrel, any consumer of that entry drags the whole Node SDK into the isolate, regardless of which binding they actually asked for.This does not affect deployed Workers, because esbuild tree-shakes the unused re-export out of the bundle. It breaks contexts that load modules unbundled, most notably
@cloudflare/vitest-pool-workers— so the code ships fine and then cannot be tested.Reproduction
Minimal standalone project — four dev-dependencies, five files, inlined in full below. Happy to push it to a repo if that's easier to work with.
package.json{ "name": "repro", "private": true, "type": "module", "devDependencies": { "@cloudflare/vitest-pool-workers": "0.18.6", "@sentry/cloudflare": "10.66.0", "vitest": "4.1.10", "wrangler": "4.112.0" } }wrangler.jsonc{ "name": "repro", "main": "worker.ts", "compatibility_date": "2026-02-19", "compatibility_flags": ["nodejs_compat"] }worker.tsvitest.config.tsrepro.test.tsnpx vitest run→Expected vs actual
Expected: the entry point imports, or fails with a catchable JS error naming the unsupported module.
Actual: the
workerdprocess dies with SIGSEGV. In a multi-file test run this silently drops the affected file — the reporter printsTest Files 4 passed (5)and a non-zero exit, with no indication of which file or why.Narrowing
Each of these was run in isolation:
import { vercelAIIntegration } from '@sentry/cloudflare'(root entry)import { vercelAIIntegration } from '@sentry/cloudflare/nodejs_compat'import { prismaIntegration } from '@sentry/node'.../build/esm/nodejs_compat/integrations/tracing/vercelai.jsSo the AI integration itself — including its
@sentry/server-utilsai:telemetrysubscriber — is perfectly workerd-safe. Only the@sentry/nodere-export in the barrel is fatal.Why this is hard to work around
Using the root entry instead is not equivalent.
build/esm/integrations/tracing/vercelai.jsimports only from@sentry/core, whereas thenodejs_compatvariant composes it withvercelAiIntegrationfrom@sentry/server-utils:Only that composed version subscribes to
ai:telemetry. With AI SDK v7 (which no longer emits OTel spans itself) the root entry produces no AI spans at all — so anyone wanting AI monitoring on Cloudflare must usenodejs_compat, which is exactly the entry that segfaults.The deep path works but is not a supported subpath:
exportsonly declares.,./requestand./nodejs_compat, so there is no public way to reach the integration without the barrel.Suggested fixes
Any one of these would resolve it:
@sentry/nodefrom a workerd entry point. LoadprismaIntegrationlazily inside the integration factory, so merely importing the barrel doesn't pull in the Node SDK.prismaIntegrationfrom the Cloudflare entry — it's a Node-only integration, and Prisma-on-Workers is its own discussion (Support Prisma Integration in Cloudflare / D1 #15466).@sentry/cloudflare/nodejs_compat/vercelai) so consumers can bypass the barrel.(1) or (2) seem cleanest, since they also shrink what every
nodejs_compatconsumer bundles.This looks like the same class of bug as #20038 (
workerd/workerexport conditions resolving to@sentry/node, breaking Cloudflare Workers).Workaround
For anyone else hitting this — alias
@sentry/nodeto a stub in the workers-pool vitest config. This makes the test module graph match what esbuild produces for production, where@sentry/nodeis absent anyway:...where the stub exports a throwing
prismaIntegration, so a genuine use fails loudly rather than silently.Environment
@sentry/cloudflare10.66.0,@sentry/server-utils10.66.0@cloudflare/vitest-pool-workers0.18.6,vitest4.1.10,wrangler4.112.0,miniflare4.20260714.0workerd1.20260714.1 — reproduced on bothworkerd-darwin-arm64(local) andworkerd-linux-64(GitHub Actionsubuntu-latest)compatibility_date2026-02-19,compatibility_flags: ["nodejs_compat"](also reproduces on 2025-10-14)