From 06534af1cb1d6c70b60b3582c5791ef7130ca29b Mon Sep 17 00:00:00 2001 From: Alexander Pantiukhov Date: Tue, 20 Oct 2026 11:36:20 +0200 Subject: [PATCH 1/2] fix(core): Match Sentry package paths with Windows separators in Metro resolvers On Windows, Metro gives `originModulePath` with backslashes. The `@sentry/browser` and `@sentry/core` origin checks searched for a forward slash, so they never matched. With `includeWebFeedback: false`, the bundle then kept `feedbackSync.js`, which calls the stubbed `buildFeedbackIntegration()` at load time and crashes the app at launch. Server-only `@sentry/core` modules also stayed in native bundles. Match both separators in the two origin checks. Fixes #6913 --- CHANGELOG.md | 1 + packages/core/src/js/tools/metroconfig.ts | 4 ++-- packages/core/test/tools/metroconfig.test.ts | 24 ++++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5dbb6ecae..852a60e443 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Fixes - Find `ios/.xcode.env` in the Expo plugin "Upload Debug Symbols to Sentry" phase when the iOS project uses Swift Package Manager instead of CocoaPods ([#6911](https://github.com/getsentry/sentry-react-native/pull/6911)) +- Remove the `@sentry/browser` feedback modules and the server-only `@sentry/core` modules from native bundles built on Windows. Before this fix, `includeWebFeedback: false` made these bundles fail at launch ([#PLACEHOLDER](https://github.com/getsentry/sentry-react-native/pull/PLACEHOLDER)) ## 8.31.0 diff --git a/packages/core/src/js/tools/metroconfig.ts b/packages/core/src/js/tools/metroconfig.ts index aab44dbf08..bb8a59d65e 100644 --- a/packages/core/src/js/tools/metroconfig.ts +++ b/packages/core/src/js/tools/metroconfig.ts @@ -384,7 +384,7 @@ export function withSentryResolver(config: MetroConfig, includeWebReplay: boolea const SENTRY_BROWSER_FEEDBACK_WRAPPER_RE = /\/feedback(Sync|Async)/; function isFromSentryBrowser(originModulePath: string): boolean { - return originModulePath.includes('@sentry/browser'); + return /[\\/]@sentry[\\/]browser[\\/]/.test(originModulePath); } /** @@ -413,7 +413,7 @@ const SERVER_ONLY_MODULE_RE = /\/(mcp-server|integrations\/(http|express|postgresjs|requestdata|consola|spanStreaming)|tracing\/(vercel-ai|openai|anthropic-ai|google-genai|langchain|langgraph)|utils\/ai)(\/|\.js|$)/; function isFromSentryCore(originModulePath: string): boolean { - return originModulePath.includes('@sentry/core'); + return /[\\/]@sentry[\\/]core[\\/]/.test(originModulePath); } /** diff --git a/packages/core/test/tools/metroconfig.test.ts b/packages/core/test/tools/metroconfig.test.ts index 94b97f02a3..dd1da0bba5 100644 --- a/packages/core/test/tools/metroconfig.test.ts +++ b/packages/core/test/tools/metroconfig.test.ts @@ -549,6 +549,18 @@ describe('metroconfig', () => { ExpectToBeCalledWithMetroParameters(originalResolverMock, browserContextMock, wrapperModule, 'web'); }); + test('removes wrapper when origin path uses Windows separators', () => { + const windowsContextMock = { + resolveRequest: jest.fn(), + originModulePath: 'C:\\project\\node_modules\\@sentry\\browser\\build\\npm\\esm\\prod\\index.js', + }; + const modifiedConfig = withSentryFeedbackResolver(config, false); + const result = resolveRequest(modifiedConfig, windowsContextMock, wrapperModule, 'ios'); + + expect(result).toEqual({ type: 'empty' }); + expect(originalResolverMock).not.toHaveBeenCalled(); + }); + test('keeps wrapper when origin is not @sentry/browser', () => { const nonBrowserContextMock = { resolveRequest: jest.fn(), @@ -713,6 +725,18 @@ describe('metroconfig', () => { }); }); + test('removes module when origin path uses Windows separators', () => { + const windowsContext = { + ...contextMock, + originModulePath: 'C:\\project\\node_modules\\@sentry\\core\\build\\esm\\index.js', + }; + const modifiedConfig = withSentryExcludeServerOnlyResolver(config); + const result = modifiedConfig.resolver?.resolveRequest?.(windowsContext, './tracing/openai/index.js', 'android'); + + expect(result).toEqual({ type: 'empty' }); + expect(originalResolverMock).not.toHaveBeenCalled(); + }); + test('does not exclude modules when origin is not @sentry/core', () => { const nonSentryContext = { ...contextMock, From 6e6fa4a088fe1cc8dbd847ca16044ac0e94bdf6e Mon Sep 17 00:00:00 2001 From: Alexander Pantiukhov Date: Tue, 20 Oct 2026 12:09:14 +0200 Subject: [PATCH 2/2] docs(core): Add PR number to the CHANGELOG entry for the Windows resolver fix Replace the placeholder with the number of the opened PR. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 852a60e443..261d6e8b70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ ### Fixes - Find `ios/.xcode.env` in the Expo plugin "Upload Debug Symbols to Sentry" phase when the iOS project uses Swift Package Manager instead of CocoaPods ([#6911](https://github.com/getsentry/sentry-react-native/pull/6911)) -- Remove the `@sentry/browser` feedback modules and the server-only `@sentry/core` modules from native bundles built on Windows. Before this fix, `includeWebFeedback: false` made these bundles fail at launch ([#PLACEHOLDER](https://github.com/getsentry/sentry-react-native/pull/PLACEHOLDER)) +- Remove the `@sentry/browser` feedback modules and the server-only `@sentry/core` modules from native bundles built on Windows. Before this fix, `includeWebFeedback: false` made these bundles fail at launch ([#6915](https://github.com/getsentry/sentry-react-native/pull/6915)) ## 8.31.0