From 32e58604b4406fc9965c72061db414dfd58cf3d8 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 29 Jul 2025 18:41:33 +0200 Subject: [PATCH 1/4] fix(browser): Handle data urls in errors caught by `globalHandlersIntegration` --- .../src/integrations/globalhandlers.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/browser/src/integrations/globalhandlers.ts b/packages/browser/src/integrations/globalhandlers.ts index ebfdff6d2f58..2aa29731a9b0 100644 --- a/packages/browser/src/integrations/globalhandlers.ts +++ b/packages/browser/src/integrations/globalhandlers.ts @@ -171,7 +171,7 @@ function _enhanceEventWithInitialFrame( const colno = column; const lineno = line; - const filename = isString(url) && url.length > 0 ? url : getLocationHref(); + const filename = getFilenameFromUrl(url) ?? getLocationHref(); // event.exception.values[0].stacktrace.frames if (ev0sf.length === 0) { @@ -199,3 +199,20 @@ function getOptions(): { stackParser: StackParser; attachStacktrace?: boolean } }; return options; } + +function getFilenameFromUrl(url: string | undefined): string | undefined { + if (!isString(url) || url.length === 0) { + return undefined; + } + + // stack frame urls can be data urls, for example when initializing a Worker with a base64 encoded script + // in this case we just show the data prefix and mime type to avoid too long raw data urls + if (url.startsWith('data:')) { + const match = url.match(/^data:([^;]+)/); + const mimeType = match ? match[1] : 'text/javascript'; + const isBase64 = url.includes('base64,'); + return ``; + } + + return url.slice(0, 1024); +} From c06aaef1bc69a34dfc1facf8eab26164266ac83d Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 7 Aug 2025 13:28:39 +0200 Subject: [PATCH 2/4] add integration test --- .../globalHandlers/dataUrls/subject.js | 11 ++++++ .../globalHandlers/dataUrls/test.ts | 36 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/test.ts diff --git a/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/subject.js b/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/subject.js new file mode 100644 index 000000000000..0c22e79964df --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/subject.js @@ -0,0 +1,11 @@ +const workerCode = ` + self.addEventListener('message', (event) => { + if (event.data.type === 'error') { + throw new Error('Error thrown in worker'); + } + }); +`; + +const worker = new Worker(`data:text/javascript;base64,${btoa(workerCode)}`); + +worker.postMessage({ type: 'error' }); diff --git a/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/test.ts b/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/test.ts new file mode 100644 index 000000000000..5c1d8a08dc90 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/test.ts @@ -0,0 +1,36 @@ +import { expect } from '@playwright/test'; +import { sentryTest } from '../../../../utils/fixtures'; +import { envelopeRequestParser, waitForErrorRequest } from '../../../../utils/helpers'; + +sentryTest('detects and handles data urls on first stack frame', async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + const errorEventPromise = waitForErrorRequest(page, e => { + return !!e.exception?.values; + }); + + await page.goto(url); + + const errorEvent = envelopeRequestParser(await errorEventPromise); + + expect(errorEvent?.exception?.values?.[0]).toEqual({ + mechanism: { + handled: false, + synthetic: true, + type: 'auto.browser.global_handlers.onerror', + }, + stacktrace: { + frames: [ + { + colno: 13, + filename: '', + function: '?', + in_app: true, + lineno: 4, + }, + ], + }, + type: 'Error', + value: 'Uncaught Error: Error thrown in worker', + }); +}); From 22ce8dccc585ba7ffe80d5861817a163e24506ae Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 7 Aug 2025 13:31:37 +0200 Subject: [PATCH 3/4] add explainer to test --- .../suites/integrations/globalHandlers/dataUrls/test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/test.ts b/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/test.ts index 5c1d8a08dc90..126d72792110 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/test.ts @@ -2,6 +2,11 @@ import { expect } from '@playwright/test'; import { sentryTest } from '../../../../utils/fixtures'; import { envelopeRequestParser, waitForErrorRequest } from '../../../../utils/helpers'; +/** + * Tests a special case where the `globalHandlersIntegration` itself creates a stack frame instead of using + * stack parsers. This is necessary because we don't always get an `error` object passed to `window.onerror`. + * @see `globalhandlers.ts#_enhanceEventWithInitialFrame` + */ sentryTest('detects and handles data urls on first stack frame', async ({ getLocalTestUrl, page }) => { const url = await getLocalTestUrl({ testDir: __dirname }); From 44a75764ebe479edc60fa81470aa70e0ef1b693d Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 7 Aug 2025 14:25:40 +0200 Subject: [PATCH 4/4] fix test --- .../suites/integrations/globalHandlers/dataUrls/test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/test.ts b/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/test.ts index 126d72792110..e890ea128069 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/globalHandlers/dataUrls/test.ts @@ -27,7 +27,7 @@ sentryTest('detects and handles data urls on first stack frame', async ({ getLoc stacktrace: { frames: [ { - colno: 13, + colno: expect.any(Number), // webkit reports different colno than chromium filename: '', function: '?', in_app: true, @@ -36,6 +36,6 @@ sentryTest('detects and handles data urls on first stack frame', async ({ getLoc ], }, type: 'Error', - value: 'Uncaught Error: Error thrown in worker', + value: expect.stringMatching(/(Uncaught )?Error: Error thrown in worker/), // webikt throws without "Uncaught " }); });