Skip to content

fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers #20038

Description

@jmalmo

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.46.0

Framework Version

TanStack Start ~1.166 (React 19, SSR via Nitro ~3.0)

Link to Sentry event

No response

Reproduction Example/SDK Setup

The core claim — that the workerd/worker conditions resolve to a file that re-exports @sentry/node — is verifiable directly from the package metadata and source without any app:

  1. Inspect packages/tanstackstart-react/package.jsonworkerd, worker, and node all resolve to index.server.js
  2. Inspect build/esm/index.server.js — does export * from '@sentry/node'

For the runtime failure:

  1. Create a TanStack Start app deployed to Cloudflare Workers (Nitro cloudflare-module preset, noExternals: true)
  2. Install @sentry/tanstackstart-react@10.46.0
  3. Import in router.tsx (SSR entry): import * as Sentry from '@sentry/tanstackstart-react'
  4. Set ssr.resolve.conditions: ['workerd', 'worker', 'browser', 'import', 'module', 'default'] in Vite config
  5. Build and deploy — the Worker returns HTTP 500 with "Cannot initialize ExportedHandler"

Because Nitro uses noExternals: true for Workers (no node_modules at runtime), the package is not externalized. Vite resolves it using ssr.resolve.conditions (not ssr.resolve.externalConditions), so the workerd condition takes effect and routes to index.server.js.

Steps to Reproduce

@sentry/tanstackstart-react advertises workerd and worker export conditions in its package.json, suggesting compatibility with Cloudflare Workers and similar edge runtimes. However, all three server-side conditions (workerd, worker, node) resolve to the exact same file — index.server.js — which re-exports @sentry/node.

The Node-orientation is not limited to the barrel re-export. The server source modules themselves import directly from @sentry/node:

When bundled for Workers (where @sentry/tanstackstart-react is non-externalized and resolved under the workerd condition), this pulls the @sentry/node dependency tree — including @opentelemetry/instrumentation-undici and transitive node:* built-in imports — into the Worker bundle. While Cloudflare Workers with nodejs_compat do support many Node APIs to varying degrees, in our deployment this caused module evaluation failure: the Worker's default export became null, producing "Cannot initialize ExportedHandler" at runtime with no stack trace. The exact failure mechanism likely depends on which node:* shims are partial or missing for the given compatibility date, but the root issue is that Workers resolves to a Node SDK entry that was never designed for this runtime.

package.json exports (v10.46.0):

{
"exports": {
".": {
"workerd": {
"import": "./build/esm/index.server.js",
"require": "./build/cjs/index.server.js"
},
"worker": {
"import": "./build/esm/index.server.js",
"require": "./build/cjs/index.server.js"
},
"browser": {
"import": "./build/esm/index.client.js",
"require": "./build/cjs/index.client.js"
},
"node": {
"import": "./build/esm/index.server.js",
"require": "./build/cjs/index.server.js"
}
}
}
}

workerd, worker, and node all resolve to index.server.js. Only browser resolves to index.client.js. The same export map is present on the develop branch, so this is a current packaging issue.

Expected Result

The workerd and worker export conditions should not resolve to code that re-exports @sentry/node.

Minimal fix — remove misleading conditions:

Remove the workerd and worker export conditions from package.json, since the package does not currently provide Workers-compatible server code. This is a packaging stopgap, not a fully non-breaking resolution:

  • Fallback behavior is toolchain-dependent. Bundlers whose active condition set includes browser (e.g., Vite with ['workerd', 'worker', 'browser', ...]) will fall through to index.client.js, which is safe. But this is not guaranteed across all resolvers — Node's package docs recommend a default branch for unknown runtimes. Whether to add default pointing to the client entry is a design call for the Sentry team.
  • Export surface change. The browser/client entry exports stubs for wrapMiddlewaresWithSentry, sentryGlobalRequestMiddleware, and sentryGlobalFunctionMiddleware, but it does not export wrapFetchWithSentry. Consumers who import that helper would get a build error. The shared index.types.ts still re-exports the full server API surface, so TypeScript types and runtime exports would diverge for Workers consumers.

Despite these caveats, removing the conditions is strictly better than the current state: it stops actively directing Workers bundlers to Node code, and the practical impact is limited since the server helpers don't work on Workers anyway.

Longer-term — proper Workers entry (follow-up):

A proper fix would create Worker-specific server modules that use @sentry/cloudflare instead of @sentry/node. This is non-trivial since @sentry/node is imported directly by multiple server source files, not just the barrel. This would likely be a separate design effort, potentially tracked alongside JS-1388.

Actual Result

Worker crashes with "Cannot initialize ExportedHandler" — silent module evaluation failure, no stack trace, no useful output from wrangler tail.

Condition resolvedServer entryWhat gets bundledResult on Workers
workerdindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
workerindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
browserindex.client.js@sentry/browser (no Node deps)Works
nodeindex.server.js@sentry/nodeWorks (Node.js)

Workaround: Replace @sentry/tanstackstart-react with @sentry/react for runtime imports. Both export init, ErrorBoundary, and tanstackRouterBrowserTracingIntegration. This preserves client-side Sentry but loses the TanStack Start server helpers. For server-side Workers tracking, use @sentry/cloudflare separately. The Vite plugin (@sentry/tanstackstart-react/vite) is build-time only and unaffected.

Related issues

  • JS-1388 — Investigate TanStack Start React Cloudflare support
  • #12620 — Sentry Cloudflare Workers SDK
  • JS-348 — Support Next.js on Cloudflare Workers (OpenNext) (same pattern with @sentry/nextjs)
  • JS-1481 — Cannot resolve @sentry/nextjs on Cloudflare Workers (same class of bug)
  • JS-377 — React Router v7 deployed to Cloudflare Workers

Additional context

Note: We are aware the SDK setup docs note this is still alpha and warn that the setup "does not currently work for Cloudflare deployments." This issue is specifically about the misleading workerd/worker export conditions — they signal bundler-level compatibility that doesn't exist, causing a silent failure mode that is very difficult to diagnose.

Environment details: Cloudflare Workers paid plan, compatibility date 2025-09-01, nodejs_compat enabled. Bundling via Vite 7 (Rolldown) with Nitro noExternals: true.

We observed platform-dependent behavior: macOS local builds sometimes tree-shook enough undici code for the Worker to boot, while Linux CI included the full transport (~900 KiB), causing module evaluation failure. This variance is secondary to the export-map mismatch but made diagnosis significantly harder.

Metadata

Metadata

Assignees

No one assigned

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    , 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
     blocks
    (function() {
    function addCopyButtons() {
    document.querySelectorAll('pre code').forEach(function(codeBlock) {
    if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
    codeBlock.parentElement.setAttribute('data-copy-added', 'true');
    var btn = document.createElement('button');
    btn.textContent = 'Copy';
    btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
    btn.onmouseover = function() { this.style.opacity = '1'; };
    btn.onmouseout = function() { this.style.opacity = '0.7'; };
    btn.onclick = function() {
    navigator.clipboard.writeText(codeBlock.textContent).then(function() {
    btn.textContent = 'Copied!';
    setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
    });
    };
    codeBlock.parentElement.style.position = 'relative';
    codeBlock.parentElement.appendChild(btn);
    });
    }
    addCopyButtons();
    // Re-run on dynamic content
    var observer = new MutationObserver(addCopyButtons);
    observer.observe(document.body, { childList: true, subtree: true });
    })();
    }
    } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
    })();
    (function(){
    try {
    var __m = "github.com";
    var __re = new RegExp('^' + "github\\.com" + '
    fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers · Issue #20038 · getsentry/sentry-javascript · GitHub
    Skip to content

    fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers #20038

    Description

    @jmalmo

    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.46.0

    Framework Version

    TanStack Start ~1.166 (React 19, SSR via Nitro ~3.0)

    Link to Sentry event

    No response

    Reproduction Example/SDK Setup

    The core claim — that the workerd/worker conditions resolve to a file that re-exports @sentry/node — is verifiable directly from the package metadata and source without any app:

    1. Inspect packages/tanstackstart-react/package.jsonworkerd, worker, and node all resolve to index.server.js
    2. Inspect build/esm/index.server.js — does export * from '@sentry/node'

    For the runtime failure:

    1. Create a TanStack Start app deployed to Cloudflare Workers (Nitro cloudflare-module preset, noExternals: true)
    2. Install @sentry/tanstackstart-react@10.46.0
    3. Import in router.tsx (SSR entry): import * as Sentry from '@sentry/tanstackstart-react'
    4. Set ssr.resolve.conditions: ['workerd', 'worker', 'browser', 'import', 'module', 'default'] in Vite config
    5. Build and deploy — the Worker returns HTTP 500 with "Cannot initialize ExportedHandler"

    Because Nitro uses noExternals: true for Workers (no node_modules at runtime), the package is not externalized. Vite resolves it using ssr.resolve.conditions (not ssr.resolve.externalConditions), so the workerd condition takes effect and routes to index.server.js.

    Steps to Reproduce

    @sentry/tanstackstart-react advertises workerd and worker export conditions in its package.json, suggesting compatibility with Cloudflare Workers and similar edge runtimes. However, all three server-side conditions (workerd, worker, node) resolve to the exact same file — index.server.js — which re-exports @sentry/node.

    The Node-orientation is not limited to the barrel re-export. The server source modules themselves import directly from @sentry/node:

    When bundled for Workers (where @sentry/tanstackstart-react is non-externalized and resolved under the workerd condition), this pulls the @sentry/node dependency tree — including @opentelemetry/instrumentation-undici and transitive node:* built-in imports — into the Worker bundle. While Cloudflare Workers with nodejs_compat do support many Node APIs to varying degrees, in our deployment this caused module evaluation failure: the Worker's default export became null, producing "Cannot initialize ExportedHandler" at runtime with no stack trace. The exact failure mechanism likely depends on which node:* shims are partial or missing for the given compatibility date, but the root issue is that Workers resolves to a Node SDK entry that was never designed for this runtime.

    package.json exports (v10.46.0):

    {
    "exports": {
    ".": {
    "workerd": {
    "import": "./build/esm/index.server.js",
    "require": "./build/cjs/index.server.js"
    },
    "worker": {
    "import": "./build/esm/index.server.js",
    "require": "./build/cjs/index.server.js"
    },
    "browser": {
    "import": "./build/esm/index.client.js",
    "require": "./build/cjs/index.client.js"
    },
    "node": {
    "import": "./build/esm/index.server.js",
    "require": "./build/cjs/index.server.js"
    }
    }
    }
    }

    workerd, worker, and node all resolve to index.server.js. Only browser resolves to index.client.js. The same export map is present on the develop branch, so this is a current packaging issue.

    Expected Result

    The workerd and worker export conditions should not resolve to code that re-exports @sentry/node.

    Minimal fix — remove misleading conditions:

    Remove the workerd and worker export conditions from package.json, since the package does not currently provide Workers-compatible server code. This is a packaging stopgap, not a fully non-breaking resolution:

    • Fallback behavior is toolchain-dependent. Bundlers whose active condition set includes browser (e.g., Vite with ['workerd', 'worker', 'browser', ...]) will fall through to index.client.js, which is safe. But this is not guaranteed across all resolvers — Node's package docs recommend a default branch for unknown runtimes. Whether to add default pointing to the client entry is a design call for the Sentry team.
    • Export surface change. The browser/client entry exports stubs for wrapMiddlewaresWithSentry, sentryGlobalRequestMiddleware, and sentryGlobalFunctionMiddleware, but it does not export wrapFetchWithSentry. Consumers who import that helper would get a build error. The shared index.types.ts still re-exports the full server API surface, so TypeScript types and runtime exports would diverge for Workers consumers.

    Despite these caveats, removing the conditions is strictly better than the current state: it stops actively directing Workers bundlers to Node code, and the practical impact is limited since the server helpers don't work on Workers anyway.

    Longer-term — proper Workers entry (follow-up):

    A proper fix would create Worker-specific server modules that use @sentry/cloudflare instead of @sentry/node. This is non-trivial since @sentry/node is imported directly by multiple server source files, not just the barrel. This would likely be a separate design effort, potentially tracked alongside JS-1388.

    Actual Result

    Worker crashes with "Cannot initialize ExportedHandler" — silent module evaluation failure, no stack trace, no useful output from wrangler tail.

    Condition resolvedServer entryWhat gets bundledResult on Workers
    workerdindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
    workerindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
    browserindex.client.js@sentry/browser (no Node deps)Works
    nodeindex.server.js@sentry/nodeWorks (Node.js)

    Workaround: Replace @sentry/tanstackstart-react with @sentry/react for runtime imports. Both export init, ErrorBoundary, and tanstackRouterBrowserTracingIntegration. This preserves client-side Sentry but loses the TanStack Start server helpers. For server-side Workers tracking, use @sentry/cloudflare separately. The Vite plugin (@sentry/tanstackstart-react/vite) is build-time only and unaffected.

    Related issues

    • JS-1388 — Investigate TanStack Start React Cloudflare support
    • #12620 — Sentry Cloudflare Workers SDK
    • JS-348 — Support Next.js on Cloudflare Workers (OpenNext) (same pattern with @sentry/nextjs)
    • JS-1481 — Cannot resolve @sentry/nextjs on Cloudflare Workers (same class of bug)
    • JS-377 — React Router v7 deployed to Cloudflare Workers

    Additional context

    Note: We are aware the SDK setup docs note this is still alpha and warn that the setup "does not currently work for Cloudflare deployments." This issue is specifically about the misleading workerd/worker export conditions — they signal bundler-level compatibility that doesn't exist, causing a silent failure mode that is very difficult to diagnose.

    Environment details: Cloudflare Workers paid plan, compatibility date 2025-09-01, nodejs_compat enabled. Bundling via Vite 7 (Rolldown) with Nitro noExternals: true.

    We observed platform-dependent behavior: macOS local builds sometimes tree-shook enough undici code for the Worker to boot, while Linux CI included the full transport (~900 KiB), causing module evaluation failure. This variance is secondary to the export-map mismatch but made diagnosis significantly harder.

    Metadata

    Metadata

    Assignees

    No one assigned

      Projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers · Issue #20038 · getsentry/sentry-javascript · GitHub
      Skip to content

      fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers #20038

      Description

      @jmalmo

      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.46.0

      Framework Version

      TanStack Start ~1.166 (React 19, SSR via Nitro ~3.0)

      Link to Sentry event

      No response

      Reproduction Example/SDK Setup

      The core claim — that the workerd/worker conditions resolve to a file that re-exports @sentry/node — is verifiable directly from the package metadata and source without any app:

      1. Inspect packages/tanstackstart-react/package.jsonworkerd, worker, and node all resolve to index.server.js
      2. Inspect build/esm/index.server.js — does export * from '@sentry/node'

      For the runtime failure:

      1. Create a TanStack Start app deployed to Cloudflare Workers (Nitro cloudflare-module preset, noExternals: true)
      2. Install @sentry/tanstackstart-react@10.46.0
      3. Import in router.tsx (SSR entry): import * as Sentry from '@sentry/tanstackstart-react'
      4. Set ssr.resolve.conditions: ['workerd', 'worker', 'browser', 'import', 'module', 'default'] in Vite config
      5. Build and deploy — the Worker returns HTTP 500 with "Cannot initialize ExportedHandler"

      Because Nitro uses noExternals: true for Workers (no node_modules at runtime), the package is not externalized. Vite resolves it using ssr.resolve.conditions (not ssr.resolve.externalConditions), so the workerd condition takes effect and routes to index.server.js.

      Steps to Reproduce

      @sentry/tanstackstart-react advertises workerd and worker export conditions in its package.json, suggesting compatibility with Cloudflare Workers and similar edge runtimes. However, all three server-side conditions (workerd, worker, node) resolve to the exact same file — index.server.js — which re-exports @sentry/node.

      The Node-orientation is not limited to the barrel re-export. The server source modules themselves import directly from @sentry/node:

      When bundled for Workers (where @sentry/tanstackstart-react is non-externalized and resolved under the workerd condition), this pulls the @sentry/node dependency tree — including @opentelemetry/instrumentation-undici and transitive node:* built-in imports — into the Worker bundle. While Cloudflare Workers with nodejs_compat do support many Node APIs to varying degrees, in our deployment this caused module evaluation failure: the Worker's default export became null, producing "Cannot initialize ExportedHandler" at runtime with no stack trace. The exact failure mechanism likely depends on which node:* shims are partial or missing for the given compatibility date, but the root issue is that Workers resolves to a Node SDK entry that was never designed for this runtime.

      package.json exports (v10.46.0):

      {
      "exports": {
      ".": {
      "workerd": {
      "import": "./build/esm/index.server.js",
      "require": "./build/cjs/index.server.js"
      },
      "worker": {
      "import": "./build/esm/index.server.js",
      "require": "./build/cjs/index.server.js"
      },
      "browser": {
      "import": "./build/esm/index.client.js",
      "require": "./build/cjs/index.client.js"
      },
      "node": {
      "import": "./build/esm/index.server.js",
      "require": "./build/cjs/index.server.js"
      }
      }
      }
      }

      workerd, worker, and node all resolve to index.server.js. Only browser resolves to index.client.js. The same export map is present on the develop branch, so this is a current packaging issue.

      Expected Result

      The workerd and worker export conditions should not resolve to code that re-exports @sentry/node.

      Minimal fix — remove misleading conditions:

      Remove the workerd and worker export conditions from package.json, since the package does not currently provide Workers-compatible server code. This is a packaging stopgap, not a fully non-breaking resolution:

      • Fallback behavior is toolchain-dependent. Bundlers whose active condition set includes browser (e.g., Vite with ['workerd', 'worker', 'browser', ...]) will fall through to index.client.js, which is safe. But this is not guaranteed across all resolvers — Node's package docs recommend a default branch for unknown runtimes. Whether to add default pointing to the client entry is a design call for the Sentry team.
      • Export surface change. The browser/client entry exports stubs for wrapMiddlewaresWithSentry, sentryGlobalRequestMiddleware, and sentryGlobalFunctionMiddleware, but it does not export wrapFetchWithSentry. Consumers who import that helper would get a build error. The shared index.types.ts still re-exports the full server API surface, so TypeScript types and runtime exports would diverge for Workers consumers.

      Despite these caveats, removing the conditions is strictly better than the current state: it stops actively directing Workers bundlers to Node code, and the practical impact is limited since the server helpers don't work on Workers anyway.

      Longer-term — proper Workers entry (follow-up):

      A proper fix would create Worker-specific server modules that use @sentry/cloudflare instead of @sentry/node. This is non-trivial since @sentry/node is imported directly by multiple server source files, not just the barrel. This would likely be a separate design effort, potentially tracked alongside JS-1388.

      Actual Result

      Worker crashes with "Cannot initialize ExportedHandler" — silent module evaluation failure, no stack trace, no useful output from wrangler tail.

      Condition resolvedServer entryWhat gets bundledResult on Workers
      workerdindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
      workerindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
      browserindex.client.js@sentry/browser (no Node deps)Works
      nodeindex.server.js@sentry/nodeWorks (Node.js)

      Workaround: Replace @sentry/tanstackstart-react with @sentry/react for runtime imports. Both export init, ErrorBoundary, and tanstackRouterBrowserTracingIntegration. This preserves client-side Sentry but loses the TanStack Start server helpers. For server-side Workers tracking, use @sentry/cloudflare separately. The Vite plugin (@sentry/tanstackstart-react/vite) is build-time only and unaffected.

      Related issues

      • JS-1388 — Investigate TanStack Start React Cloudflare support
      • #12620 — Sentry Cloudflare Workers SDK
      • JS-348 — Support Next.js on Cloudflare Workers (OpenNext) (same pattern with @sentry/nextjs)
      • JS-1481 — Cannot resolve @sentry/nextjs on Cloudflare Workers (same class of bug)
      • JS-377 — React Router v7 deployed to Cloudflare Workers

      Additional context

      Note: We are aware the SDK setup docs note this is still alpha and warn that the setup "does not currently work for Cloudflare deployments." This issue is specifically about the misleading workerd/worker export conditions — they signal bundler-level compatibility that doesn't exist, causing a silent failure mode that is very difficult to diagnose.

      Environment details: Cloudflare Workers paid plan, compatibility date 2025-09-01, nodejs_compat enabled. Bundling via Vite 7 (Rolldown) with Nitro noExternals: true.

      We observed platform-dependent behavior: macOS local builds sometimes tree-shook enough undici code for the Worker to boot, while Linux CI included the full transport (~900 KiB), causing module evaluation failure. This variance is secondary to the export-map mismatch but made diagnosis significantly harder.

      Metadata

      Metadata

      Assignees

      No one assigned

        Projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions

        , 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers · Issue #20038 · getsentry/sentry-javascript · GitHub
        Skip to content

        fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers #20038

        Description

        @jmalmo

        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.46.0

        Framework Version

        TanStack Start ~1.166 (React 19, SSR via Nitro ~3.0)

        Link to Sentry event

        No response

        Reproduction Example/SDK Setup

        The core claim — that the workerd/worker conditions resolve to a file that re-exports @sentry/node — is verifiable directly from the package metadata and source without any app:

        1. Inspect packages/tanstackstart-react/package.jsonworkerd, worker, and node all resolve to index.server.js
        2. Inspect build/esm/index.server.js — does export * from '@sentry/node'

        For the runtime failure:

        1. Create a TanStack Start app deployed to Cloudflare Workers (Nitro cloudflare-module preset, noExternals: true)
        2. Install @sentry/tanstackstart-react@10.46.0
        3. Import in router.tsx (SSR entry): import * as Sentry from '@sentry/tanstackstart-react'
        4. Set ssr.resolve.conditions: ['workerd', 'worker', 'browser', 'import', 'module', 'default'] in Vite config
        5. Build and deploy — the Worker returns HTTP 500 with "Cannot initialize ExportedHandler"

        Because Nitro uses noExternals: true for Workers (no node_modules at runtime), the package is not externalized. Vite resolves it using ssr.resolve.conditions (not ssr.resolve.externalConditions), so the workerd condition takes effect and routes to index.server.js.

        Steps to Reproduce

        @sentry/tanstackstart-react advertises workerd and worker export conditions in its package.json, suggesting compatibility with Cloudflare Workers and similar edge runtimes. However, all three server-side conditions (workerd, worker, node) resolve to the exact same file — index.server.js — which re-exports @sentry/node.

        The Node-orientation is not limited to the barrel re-export. The server source modules themselves import directly from @sentry/node:

        When bundled for Workers (where @sentry/tanstackstart-react is non-externalized and resolved under the workerd condition), this pulls the @sentry/node dependency tree — including @opentelemetry/instrumentation-undici and transitive node:* built-in imports — into the Worker bundle. While Cloudflare Workers with nodejs_compat do support many Node APIs to varying degrees, in our deployment this caused module evaluation failure: the Worker's default export became null, producing "Cannot initialize ExportedHandler" at runtime with no stack trace. The exact failure mechanism likely depends on which node:* shims are partial or missing for the given compatibility date, but the root issue is that Workers resolves to a Node SDK entry that was never designed for this runtime.

        package.json exports (v10.46.0):

        {
        "exports": {
        ".": {
        "workerd": {
        "import": "./build/esm/index.server.js",
        "require": "./build/cjs/index.server.js"
        },
        "worker": {
        "import": "./build/esm/index.server.js",
        "require": "./build/cjs/index.server.js"
        },
        "browser": {
        "import": "./build/esm/index.client.js",
        "require": "./build/cjs/index.client.js"
        },
        "node": {
        "import": "./build/esm/index.server.js",
        "require": "./build/cjs/index.server.js"
        }
        }
        }
        }

        workerd, worker, and node all resolve to index.server.js. Only browser resolves to index.client.js. The same export map is present on the develop branch, so this is a current packaging issue.

        Expected Result

        The workerd and worker export conditions should not resolve to code that re-exports @sentry/node.

        Minimal fix — remove misleading conditions:

        Remove the workerd and worker export conditions from package.json, since the package does not currently provide Workers-compatible server code. This is a packaging stopgap, not a fully non-breaking resolution:

        • Fallback behavior is toolchain-dependent. Bundlers whose active condition set includes browser (e.g., Vite with ['workerd', 'worker', 'browser', ...]) will fall through to index.client.js, which is safe. But this is not guaranteed across all resolvers — Node's package docs recommend a default branch for unknown runtimes. Whether to add default pointing to the client entry is a design call for the Sentry team.
        • Export surface change. The browser/client entry exports stubs for wrapMiddlewaresWithSentry, sentryGlobalRequestMiddleware, and sentryGlobalFunctionMiddleware, but it does not export wrapFetchWithSentry. Consumers who import that helper would get a build error. The shared index.types.ts still re-exports the full server API surface, so TypeScript types and runtime exports would diverge for Workers consumers.

        Despite these caveats, removing the conditions is strictly better than the current state: it stops actively directing Workers bundlers to Node code, and the practical impact is limited since the server helpers don't work on Workers anyway.

        Longer-term — proper Workers entry (follow-up):

        A proper fix would create Worker-specific server modules that use @sentry/cloudflare instead of @sentry/node. This is non-trivial since @sentry/node is imported directly by multiple server source files, not just the barrel. This would likely be a separate design effort, potentially tracked alongside JS-1388.

        Actual Result

        Worker crashes with "Cannot initialize ExportedHandler" — silent module evaluation failure, no stack trace, no useful output from wrangler tail.

        Condition resolvedServer entryWhat gets bundledResult on Workers
        workerdindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
        workerindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
        browserindex.client.js@sentry/browser (no Node deps)Works
        nodeindex.server.js@sentry/nodeWorks (Node.js)

        Workaround: Replace @sentry/tanstackstart-react with @sentry/react for runtime imports. Both export init, ErrorBoundary, and tanstackRouterBrowserTracingIntegration. This preserves client-side Sentry but loses the TanStack Start server helpers. For server-side Workers tracking, use @sentry/cloudflare separately. The Vite plugin (@sentry/tanstackstart-react/vite) is build-time only and unaffected.

        Related issues

        • JS-1388 — Investigate TanStack Start React Cloudflare support
        • #12620 — Sentry Cloudflare Workers SDK
        • JS-348 — Support Next.js on Cloudflare Workers (OpenNext) (same pattern with @sentry/nextjs)
        • JS-1481 — Cannot resolve @sentry/nextjs on Cloudflare Workers (same class of bug)
        • JS-377 — React Router v7 deployed to Cloudflare Workers

        Additional context

        Note: We are aware the SDK setup docs note this is still alpha and warn that the setup "does not currently work for Cloudflare deployments." This issue is specifically about the misleading workerd/worker export conditions — they signal bundler-level compatibility that doesn't exist, causing a silent failure mode that is very difficult to diagnose.

        Environment details: Cloudflare Workers paid plan, compatibility date 2025-09-01, nodejs_compat enabled. Bundling via Vite 7 (Rolldown) with Nitro noExternals: true.

        We observed platform-dependent behavior: macOS local builds sometimes tree-shook enough undici code for the Worker to boot, while Linux CI included the full transport (~900 KiB), causing module evaluation failure. This variance is secondary to the export-map mismatch but made diagnosis significantly harder.

        Metadata

        Metadata

        Assignees

        No one assigned

          Projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers · Issue #20038 · getsentry/sentry-javascript · GitHub
          Skip to content

          fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers #20038

          Description

          @jmalmo

          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.46.0

          Framework Version

          TanStack Start ~1.166 (React 19, SSR via Nitro ~3.0)

          Link to Sentry event

          No response

          Reproduction Example/SDK Setup

          The core claim — that the workerd/worker conditions resolve to a file that re-exports @sentry/node — is verifiable directly from the package metadata and source without any app:

          1. Inspect packages/tanstackstart-react/package.jsonworkerd, worker, and node all resolve to index.server.js
          2. Inspect build/esm/index.server.js — does export * from '@sentry/node'

          For the runtime failure:

          1. Create a TanStack Start app deployed to Cloudflare Workers (Nitro cloudflare-module preset, noExternals: true)
          2. Install @sentry/tanstackstart-react@10.46.0
          3. Import in router.tsx (SSR entry): import * as Sentry from '@sentry/tanstackstart-react'
          4. Set ssr.resolve.conditions: ['workerd', 'worker', 'browser', 'import', 'module', 'default'] in Vite config
          5. Build and deploy — the Worker returns HTTP 500 with "Cannot initialize ExportedHandler"

          Because Nitro uses noExternals: true for Workers (no node_modules at runtime), the package is not externalized. Vite resolves it using ssr.resolve.conditions (not ssr.resolve.externalConditions), so the workerd condition takes effect and routes to index.server.js.

          Steps to Reproduce

          @sentry/tanstackstart-react advertises workerd and worker export conditions in its package.json, suggesting compatibility with Cloudflare Workers and similar edge runtimes. However, all three server-side conditions (workerd, worker, node) resolve to the exact same file — index.server.js — which re-exports @sentry/node.

          The Node-orientation is not limited to the barrel re-export. The server source modules themselves import directly from @sentry/node:

          When bundled for Workers (where @sentry/tanstackstart-react is non-externalized and resolved under the workerd condition), this pulls the @sentry/node dependency tree — including @opentelemetry/instrumentation-undici and transitive node:* built-in imports — into the Worker bundle. While Cloudflare Workers with nodejs_compat do support many Node APIs to varying degrees, in our deployment this caused module evaluation failure: the Worker's default export became null, producing "Cannot initialize ExportedHandler" at runtime with no stack trace. The exact failure mechanism likely depends on which node:* shims are partial or missing for the given compatibility date, but the root issue is that Workers resolves to a Node SDK entry that was never designed for this runtime.

          package.json exports (v10.46.0):

          {
          "exports": {
          ".": {
          "workerd": {
          "import": "./build/esm/index.server.js",
          "require": "./build/cjs/index.server.js"
          },
          "worker": {
          "import": "./build/esm/index.server.js",
          "require": "./build/cjs/index.server.js"
          },
          "browser": {
          "import": "./build/esm/index.client.js",
          "require": "./build/cjs/index.client.js"
          },
          "node": {
          "import": "./build/esm/index.server.js",
          "require": "./build/cjs/index.server.js"
          }
          }
          }
          }

          workerd, worker, and node all resolve to index.server.js. Only browser resolves to index.client.js. The same export map is present on the develop branch, so this is a current packaging issue.

          Expected Result

          The workerd and worker export conditions should not resolve to code that re-exports @sentry/node.

          Minimal fix — remove misleading conditions:

          Remove the workerd and worker export conditions from package.json, since the package does not currently provide Workers-compatible server code. This is a packaging stopgap, not a fully non-breaking resolution:

          • Fallback behavior is toolchain-dependent. Bundlers whose active condition set includes browser (e.g., Vite with ['workerd', 'worker', 'browser', ...]) will fall through to index.client.js, which is safe. But this is not guaranteed across all resolvers — Node's package docs recommend a default branch for unknown runtimes. Whether to add default pointing to the client entry is a design call for the Sentry team.
          • Export surface change. The browser/client entry exports stubs for wrapMiddlewaresWithSentry, sentryGlobalRequestMiddleware, and sentryGlobalFunctionMiddleware, but it does not export wrapFetchWithSentry. Consumers who import that helper would get a build error. The shared index.types.ts still re-exports the full server API surface, so TypeScript types and runtime exports would diverge for Workers consumers.

          Despite these caveats, removing the conditions is strictly better than the current state: it stops actively directing Workers bundlers to Node code, and the practical impact is limited since the server helpers don't work on Workers anyway.

          Longer-term — proper Workers entry (follow-up):

          A proper fix would create Worker-specific server modules that use @sentry/cloudflare instead of @sentry/node. This is non-trivial since @sentry/node is imported directly by multiple server source files, not just the barrel. This would likely be a separate design effort, potentially tracked alongside JS-1388.

          Actual Result

          Worker crashes with "Cannot initialize ExportedHandler" — silent module evaluation failure, no stack trace, no useful output from wrangler tail.

          Condition resolvedServer entryWhat gets bundledResult on Workers
          workerdindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
          workerindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
          browserindex.client.js@sentry/browser (no Node deps)Works
          nodeindex.server.js@sentry/nodeWorks (Node.js)

          Workaround: Replace @sentry/tanstackstart-react with @sentry/react for runtime imports. Both export init, ErrorBoundary, and tanstackRouterBrowserTracingIntegration. This preserves client-side Sentry but loses the TanStack Start server helpers. For server-side Workers tracking, use @sentry/cloudflare separately. The Vite plugin (@sentry/tanstackstart-react/vite) is build-time only and unaffected.

          Related issues

          • JS-1388 — Investigate TanStack Start React Cloudflare support
          • #12620 — Sentry Cloudflare Workers SDK
          • JS-348 — Support Next.js on Cloudflare Workers (OpenNext) (same pattern with @sentry/nextjs)
          • JS-1481 — Cannot resolve @sentry/nextjs on Cloudflare Workers (same class of bug)
          • JS-377 — React Router v7 deployed to Cloudflare Workers

          Additional context

          Note: We are aware the SDK setup docs note this is still alpha and warn that the setup "does not currently work for Cloudflare deployments." This issue is specifically about the misleading workerd/worker export conditions — they signal bundler-level compatibility that doesn't exist, causing a silent failure mode that is very difficult to diagnose.

          Environment details: Cloudflare Workers paid plan, compatibility date 2025-09-01, nodejs_compat enabled. Bundling via Vite 7 (Rolldown) with Nitro noExternals: true.

          We observed platform-dependent behavior: macOS local builds sometimes tree-shook enough undici code for the Worker to boot, while Linux CI included the full transport (~900 KiB), causing module evaluation failure. This variance is secondary to the export-map mismatch but made diagnosis significantly harder.

          Metadata

          Metadata

          Assignees

          No one assigned

            Projects

            Milestone

            No milestone

            Relationships

            None yet

            Development

            No branches or pull requests

            Issue actions

            , 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers · Issue #20038 · getsentry/sentry-javascript · GitHub
            Skip to content

            fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers #20038

            Description

            @jmalmo

            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.46.0

            Framework Version

            TanStack Start ~1.166 (React 19, SSR via Nitro ~3.0)

            Link to Sentry event

            No response

            Reproduction Example/SDK Setup

            The core claim — that the workerd/worker conditions resolve to a file that re-exports @sentry/node — is verifiable directly from the package metadata and source without any app:

            1. Inspect packages/tanstackstart-react/package.jsonworkerd, worker, and node all resolve to index.server.js
            2. Inspect build/esm/index.server.js — does export * from '@sentry/node'

            For the runtime failure:

            1. Create a TanStack Start app deployed to Cloudflare Workers (Nitro cloudflare-module preset, noExternals: true)
            2. Install @sentry/tanstackstart-react@10.46.0
            3. Import in router.tsx (SSR entry): import * as Sentry from '@sentry/tanstackstart-react'
            4. Set ssr.resolve.conditions: ['workerd', 'worker', 'browser', 'import', 'module', 'default'] in Vite config
            5. Build and deploy — the Worker returns HTTP 500 with "Cannot initialize ExportedHandler"

            Because Nitro uses noExternals: true for Workers (no node_modules at runtime), the package is not externalized. Vite resolves it using ssr.resolve.conditions (not ssr.resolve.externalConditions), so the workerd condition takes effect and routes to index.server.js.

            Steps to Reproduce

            @sentry/tanstackstart-react advertises workerd and worker export conditions in its package.json, suggesting compatibility with Cloudflare Workers and similar edge runtimes. However, all three server-side conditions (workerd, worker, node) resolve to the exact same file — index.server.js — which re-exports @sentry/node.

            The Node-orientation is not limited to the barrel re-export. The server source modules themselves import directly from @sentry/node:

            When bundled for Workers (where @sentry/tanstackstart-react is non-externalized and resolved under the workerd condition), this pulls the @sentry/node dependency tree — including @opentelemetry/instrumentation-undici and transitive node:* built-in imports — into the Worker bundle. While Cloudflare Workers with nodejs_compat do support many Node APIs to varying degrees, in our deployment this caused module evaluation failure: the Worker's default export became null, producing "Cannot initialize ExportedHandler" at runtime with no stack trace. The exact failure mechanism likely depends on which node:* shims are partial or missing for the given compatibility date, but the root issue is that Workers resolves to a Node SDK entry that was never designed for this runtime.

            package.json exports (v10.46.0):

            {
            "exports": {
            ".": {
            "workerd": {
            "import": "./build/esm/index.server.js",
            "require": "./build/cjs/index.server.js"
            },
            "worker": {
            "import": "./build/esm/index.server.js",
            "require": "./build/cjs/index.server.js"
            },
            "browser": {
            "import": "./build/esm/index.client.js",
            "require": "./build/cjs/index.client.js"
            },
            "node": {
            "import": "./build/esm/index.server.js",
            "require": "./build/cjs/index.server.js"
            }
            }
            }
            }

            workerd, worker, and node all resolve to index.server.js. Only browser resolves to index.client.js. The same export map is present on the develop branch, so this is a current packaging issue.

            Expected Result

            The workerd and worker export conditions should not resolve to code that re-exports @sentry/node.

            Minimal fix — remove misleading conditions:

            Remove the workerd and worker export conditions from package.json, since the package does not currently provide Workers-compatible server code. This is a packaging stopgap, not a fully non-breaking resolution:

            • Fallback behavior is toolchain-dependent. Bundlers whose active condition set includes browser (e.g., Vite with ['workerd', 'worker', 'browser', ...]) will fall through to index.client.js, which is safe. But this is not guaranteed across all resolvers — Node's package docs recommend a default branch for unknown runtimes. Whether to add default pointing to the client entry is a design call for the Sentry team.
            • Export surface change. The browser/client entry exports stubs for wrapMiddlewaresWithSentry, sentryGlobalRequestMiddleware, and sentryGlobalFunctionMiddleware, but it does not export wrapFetchWithSentry. Consumers who import that helper would get a build error. The shared index.types.ts still re-exports the full server API surface, so TypeScript types and runtime exports would diverge for Workers consumers.

            Despite these caveats, removing the conditions is strictly better than the current state: it stops actively directing Workers bundlers to Node code, and the practical impact is limited since the server helpers don't work on Workers anyway.

            Longer-term — proper Workers entry (follow-up):

            A proper fix would create Worker-specific server modules that use @sentry/cloudflare instead of @sentry/node. This is non-trivial since @sentry/node is imported directly by multiple server source files, not just the barrel. This would likely be a separate design effort, potentially tracked alongside JS-1388.

            Actual Result

            Worker crashes with "Cannot initialize ExportedHandler" — silent module evaluation failure, no stack trace, no useful output from wrangler tail.

            Condition resolvedServer entryWhat gets bundledResult on Workers
            workerdindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
            workerindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
            browserindex.client.js@sentry/browser (no Node deps)Works
            nodeindex.server.js@sentry/nodeWorks (Node.js)

            Workaround: Replace @sentry/tanstackstart-react with @sentry/react for runtime imports. Both export init, ErrorBoundary, and tanstackRouterBrowserTracingIntegration. This preserves client-side Sentry but loses the TanStack Start server helpers. For server-side Workers tracking, use @sentry/cloudflare separately. The Vite plugin (@sentry/tanstackstart-react/vite) is build-time only and unaffected.

            Related issues

            • JS-1388 — Investigate TanStack Start React Cloudflare support
            • #12620 — Sentry Cloudflare Workers SDK
            • JS-348 — Support Next.js on Cloudflare Workers (OpenNext) (same pattern with @sentry/nextjs)
            • JS-1481 — Cannot resolve @sentry/nextjs on Cloudflare Workers (same class of bug)
            • JS-377 — React Router v7 deployed to Cloudflare Workers

            Additional context

            Note: We are aware the SDK setup docs note this is still alpha and warn that the setup "does not currently work for Cloudflare deployments." This issue is specifically about the misleading workerd/worker export conditions — they signal bundler-level compatibility that doesn't exist, causing a silent failure mode that is very difficult to diagnose.

            Environment details: Cloudflare Workers paid plan, compatibility date 2025-09-01, nodejs_compat enabled. Bundling via Vite 7 (Rolldown) with Nitro noExternals: true.

            We observed platform-dependent behavior: macOS local builds sometimes tree-shook enough undici code for the Worker to boot, while Linux CI included the full transport (~900 KiB), causing module evaluation failure. This variance is secondary to the export-map mismatch but made diagnosis significantly harder.

            Metadata

            Metadata

            Assignees

            No one assigned

              Projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers · Issue #20038 · getsentry/sentry-javascript · GitHub
              Skip to content

              fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers #20038

              Description

              @jmalmo

              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.46.0

              Framework Version

              TanStack Start ~1.166 (React 19, SSR via Nitro ~3.0)

              Link to Sentry event

              No response

              Reproduction Example/SDK Setup

              The core claim — that the workerd/worker conditions resolve to a file that re-exports @sentry/node — is verifiable directly from the package metadata and source without any app:

              1. Inspect packages/tanstackstart-react/package.jsonworkerd, worker, and node all resolve to index.server.js
              2. Inspect build/esm/index.server.js — does export * from '@sentry/node'

              For the runtime failure:

              1. Create a TanStack Start app deployed to Cloudflare Workers (Nitro cloudflare-module preset, noExternals: true)
              2. Install @sentry/tanstackstart-react@10.46.0
              3. Import in router.tsx (SSR entry): import * as Sentry from '@sentry/tanstackstart-react'
              4. Set ssr.resolve.conditions: ['workerd', 'worker', 'browser', 'import', 'module', 'default'] in Vite config
              5. Build and deploy — the Worker returns HTTP 500 with "Cannot initialize ExportedHandler"

              Because Nitro uses noExternals: true for Workers (no node_modules at runtime), the package is not externalized. Vite resolves it using ssr.resolve.conditions (not ssr.resolve.externalConditions), so the workerd condition takes effect and routes to index.server.js.

              Steps to Reproduce

              @sentry/tanstackstart-react advertises workerd and worker export conditions in its package.json, suggesting compatibility with Cloudflare Workers and similar edge runtimes. However, all three server-side conditions (workerd, worker, node) resolve to the exact same file — index.server.js — which re-exports @sentry/node.

              The Node-orientation is not limited to the barrel re-export. The server source modules themselves import directly from @sentry/node:

              When bundled for Workers (where @sentry/tanstackstart-react is non-externalized and resolved under the workerd condition), this pulls the @sentry/node dependency tree — including @opentelemetry/instrumentation-undici and transitive node:* built-in imports — into the Worker bundle. While Cloudflare Workers with nodejs_compat do support many Node APIs to varying degrees, in our deployment this caused module evaluation failure: the Worker's default export became null, producing "Cannot initialize ExportedHandler" at runtime with no stack trace. The exact failure mechanism likely depends on which node:* shims are partial or missing for the given compatibility date, but the root issue is that Workers resolves to a Node SDK entry that was never designed for this runtime.

              package.json exports (v10.46.0):

              {
              "exports": {
              ".": {
              "workerd": {
              "import": "./build/esm/index.server.js",
              "require": "./build/cjs/index.server.js"
              },
              "worker": {
              "import": "./build/esm/index.server.js",
              "require": "./build/cjs/index.server.js"
              },
              "browser": {
              "import": "./build/esm/index.client.js",
              "require": "./build/cjs/index.client.js"
              },
              "node": {
              "import": "./build/esm/index.server.js",
              "require": "./build/cjs/index.server.js"
              }
              }
              }
              }

              workerd, worker, and node all resolve to index.server.js. Only browser resolves to index.client.js. The same export map is present on the develop branch, so this is a current packaging issue.

              Expected Result

              The workerd and worker export conditions should not resolve to code that re-exports @sentry/node.

              Minimal fix — remove misleading conditions:

              Remove the workerd and worker export conditions from package.json, since the package does not currently provide Workers-compatible server code. This is a packaging stopgap, not a fully non-breaking resolution:

              • Fallback behavior is toolchain-dependent. Bundlers whose active condition set includes browser (e.g., Vite with ['workerd', 'worker', 'browser', ...]) will fall through to index.client.js, which is safe. But this is not guaranteed across all resolvers — Node's package docs recommend a default branch for unknown runtimes. Whether to add default pointing to the client entry is a design call for the Sentry team.
              • Export surface change. The browser/client entry exports stubs for wrapMiddlewaresWithSentry, sentryGlobalRequestMiddleware, and sentryGlobalFunctionMiddleware, but it does not export wrapFetchWithSentry. Consumers who import that helper would get a build error. The shared index.types.ts still re-exports the full server API surface, so TypeScript types and runtime exports would diverge for Workers consumers.

              Despite these caveats, removing the conditions is strictly better than the current state: it stops actively directing Workers bundlers to Node code, and the practical impact is limited since the server helpers don't work on Workers anyway.

              Longer-term — proper Workers entry (follow-up):

              A proper fix would create Worker-specific server modules that use @sentry/cloudflare instead of @sentry/node. This is non-trivial since @sentry/node is imported directly by multiple server source files, not just the barrel. This would likely be a separate design effort, potentially tracked alongside JS-1388.

              Actual Result

              Worker crashes with "Cannot initialize ExportedHandler" — silent module evaluation failure, no stack trace, no useful output from wrangler tail.

              Condition resolvedServer entryWhat gets bundledResult on Workers
              workerdindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
              workerindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
              browserindex.client.js@sentry/browser (no Node deps)Works
              nodeindex.server.js@sentry/nodeWorks (Node.js)

              Workaround: Replace @sentry/tanstackstart-react with @sentry/react for runtime imports. Both export init, ErrorBoundary, and tanstackRouterBrowserTracingIntegration. This preserves client-side Sentry but loses the TanStack Start server helpers. For server-side Workers tracking, use @sentry/cloudflare separately. The Vite plugin (@sentry/tanstackstart-react/vite) is build-time only and unaffected.

              Related issues

              • JS-1388 — Investigate TanStack Start React Cloudflare support
              • #12620 — Sentry Cloudflare Workers SDK
              • JS-348 — Support Next.js on Cloudflare Workers (OpenNext) (same pattern with @sentry/nextjs)
              • JS-1481 — Cannot resolve @sentry/nextjs on Cloudflare Workers (same class of bug)
              • JS-377 — React Router v7 deployed to Cloudflare Workers

              Additional context

              Note: We are aware the SDK setup docs note this is still alpha and warn that the setup "does not currently work for Cloudflare deployments." This issue is specifically about the misleading workerd/worker export conditions — they signal bundler-level compatibility that doesn't exist, causing a silent failure mode that is very difficult to diagnose.

              Environment details: Cloudflare Workers paid plan, compatibility date 2025-09-01, nodejs_compat enabled. Bundling via Vite 7 (Rolldown) with Nitro noExternals: true.

              We observed platform-dependent behavior: macOS local builds sometimes tree-shook enough undici code for the Worker to boot, while Linux CI included the full transport (~900 KiB), causing module evaluation failure. This variance is secondary to the export-map mismatch but made diagnosis significantly harder.

              Metadata

              Metadata

              Assignees

              No one assigned

                Projects

                Milestone

                No milestone

                Relationships

                None yet

                Development

                No branches or pull requests

                Issue actions

                , 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers · Issue #20038 · getsentry/sentry-javascript · GitHub
                Skip to content

                fix(tanstackstart-react): workerd/worker export conditions resolve to @sentry/node, breaking Cloudflare Workers #20038

                Description

                @jmalmo

                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.46.0

                Framework Version

                TanStack Start ~1.166 (React 19, SSR via Nitro ~3.0)

                Link to Sentry event

                No response

                Reproduction Example/SDK Setup

                The core claim — that the workerd/worker conditions resolve to a file that re-exports @sentry/node — is verifiable directly from the package metadata and source without any app:

                1. Inspect packages/tanstackstart-react/package.jsonworkerd, worker, and node all resolve to index.server.js
                2. Inspect build/esm/index.server.js — does export * from '@sentry/node'

                For the runtime failure:

                1. Create a TanStack Start app deployed to Cloudflare Workers (Nitro cloudflare-module preset, noExternals: true)
                2. Install @sentry/tanstackstart-react@10.46.0
                3. Import in router.tsx (SSR entry): import * as Sentry from '@sentry/tanstackstart-react'
                4. Set ssr.resolve.conditions: ['workerd', 'worker', 'browser', 'import', 'module', 'default'] in Vite config
                5. Build and deploy — the Worker returns HTTP 500 with "Cannot initialize ExportedHandler"

                Because Nitro uses noExternals: true for Workers (no node_modules at runtime), the package is not externalized. Vite resolves it using ssr.resolve.conditions (not ssr.resolve.externalConditions), so the workerd condition takes effect and routes to index.server.js.

                Steps to Reproduce

                @sentry/tanstackstart-react advertises workerd and worker export conditions in its package.json, suggesting compatibility with Cloudflare Workers and similar edge runtimes. However, all three server-side conditions (workerd, worker, node) resolve to the exact same file — index.server.js — which re-exports @sentry/node.

                The Node-orientation is not limited to the barrel re-export. The server source modules themselves import directly from @sentry/node:

                When bundled for Workers (where @sentry/tanstackstart-react is non-externalized and resolved under the workerd condition), this pulls the @sentry/node dependency tree — including @opentelemetry/instrumentation-undici and transitive node:* built-in imports — into the Worker bundle. While Cloudflare Workers with nodejs_compat do support many Node APIs to varying degrees, in our deployment this caused module evaluation failure: the Worker's default export became null, producing "Cannot initialize ExportedHandler" at runtime with no stack trace. The exact failure mechanism likely depends on which node:* shims are partial or missing for the given compatibility date, but the root issue is that Workers resolves to a Node SDK entry that was never designed for this runtime.

                package.json exports (v10.46.0):

                {
                "exports": {
                ".": {
                "workerd": {
                "import": "./build/esm/index.server.js",
                "require": "./build/cjs/index.server.js"
                },
                "worker": {
                "import": "./build/esm/index.server.js",
                "require": "./build/cjs/index.server.js"
                },
                "browser": {
                "import": "./build/esm/index.client.js",
                "require": "./build/cjs/index.client.js"
                },
                "node": {
                "import": "./build/esm/index.server.js",
                "require": "./build/cjs/index.server.js"
                }
                }
                }
                }

                workerd, worker, and node all resolve to index.server.js. Only browser resolves to index.client.js. The same export map is present on the develop branch, so this is a current packaging issue.

                Expected Result

                The workerd and worker export conditions should not resolve to code that re-exports @sentry/node.

                Minimal fix — remove misleading conditions:

                Remove the workerd and worker export conditions from package.json, since the package does not currently provide Workers-compatible server code. This is a packaging stopgap, not a fully non-breaking resolution:

                • Fallback behavior is toolchain-dependent. Bundlers whose active condition set includes browser (e.g., Vite with ['workerd', 'worker', 'browser', ...]) will fall through to index.client.js, which is safe. But this is not guaranteed across all resolvers — Node's package docs recommend a default branch for unknown runtimes. Whether to add default pointing to the client entry is a design call for the Sentry team.
                • Export surface change. The browser/client entry exports stubs for wrapMiddlewaresWithSentry, sentryGlobalRequestMiddleware, and sentryGlobalFunctionMiddleware, but it does not export wrapFetchWithSentry. Consumers who import that helper would get a build error. The shared index.types.ts still re-exports the full server API surface, so TypeScript types and runtime exports would diverge for Workers consumers.

                Despite these caveats, removing the conditions is strictly better than the current state: it stops actively directing Workers bundlers to Node code, and the practical impact is limited since the server helpers don't work on Workers anyway.

                Longer-term — proper Workers entry (follow-up):

                A proper fix would create Worker-specific server modules that use @sentry/cloudflare instead of @sentry/node. This is non-trivial since @sentry/node is imported directly by multiple server source files, not just the barrel. This would likely be a separate design effort, potentially tracked alongside JS-1388.

                Actual Result

                Worker crashes with "Cannot initialize ExportedHandler" — silent module evaluation failure, no stack trace, no useful output from wrangler tail.

                Condition resolvedServer entryWhat gets bundledResult on Workers
                workerdindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
                workerindex.server.js@sentry/node + OpenTelemetry + node:*Silent crash
                browserindex.client.js@sentry/browser (no Node deps)Works
                nodeindex.server.js@sentry/nodeWorks (Node.js)

                Workaround: Replace @sentry/tanstackstart-react with @sentry/react for runtime imports. Both export init, ErrorBoundary, and tanstackRouterBrowserTracingIntegration. This preserves client-side Sentry but loses the TanStack Start server helpers. For server-side Workers tracking, use @sentry/cloudflare separately. The Vite plugin (@sentry/tanstackstart-react/vite) is build-time only and unaffected.

                Related issues

                • JS-1388 — Investigate TanStack Start React Cloudflare support
                • #12620 — Sentry Cloudflare Workers SDK
                • JS-348 — Support Next.js on Cloudflare Workers (OpenNext) (same pattern with @sentry/nextjs)
                • JS-1481 — Cannot resolve @sentry/nextjs on Cloudflare Workers (same class of bug)
                • JS-377 — React Router v7 deployed to Cloudflare Workers

                Additional context

                Note: We are aware the SDK setup docs note this is still alpha and warn that the setup "does not currently work for Cloudflare deployments." This issue is specifically about the misleading workerd/worker export conditions — they signal bundler-level compatibility that doesn't exist, causing a silent failure mode that is very difficult to diagnose.

                Environment details: Cloudflare Workers paid plan, compatibility date 2025-09-01, nodejs_compat enabled. Bundling via Vite 7 (Rolldown) with Nitro noExternals: true.

                We observed platform-dependent behavior: macOS local builds sometimes tree-shook enough undici code for the Worker to boot, while Linux CI included the full transport (~900 KiB), causing module evaluation failure. This variance is secondary to the export-map mismatch but made diagnosis significantly harder.

                Metadata

                Metadata

                Assignees

                No one assigned

                  Projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions