From 0f76c4448861945a6ca223f0d3428877dc4e4412 Mon Sep 17 00:00:00 2001 From: abcang Date: Thu, 26 Mar 2026 20:00:39 +0900 Subject: [PATCH 1/2] fix(browser): Add a synthetic stack trace to DOMException with empty stack traces if attachStacktrace is true --- packages/browser/src/eventbuilder.ts | 2 +- packages/browser/test/eventbuilder.test.ts | 75 ++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/packages/browser/src/eventbuilder.ts b/packages/browser/src/eventbuilder.ts index b430007b552d..4ddd82e837cc 100644 --- a/packages/browser/src/eventbuilder.ts +++ b/packages/browser/src/eventbuilder.ts @@ -288,7 +288,7 @@ export function eventFromUnknownInput( if (isDOMError(exception) || isDOMException(exception as DOMException)) { const domException = exception as DOMException; - if ('stack' in (exception as Error)) { + if ((exception as Error).stack) { event = eventFromError(stackParser, exception as Error); } else { const name = domException.name || (isDOMError(domException) ? 'DOMError' : 'DOMException'); diff --git a/packages/browser/test/eventbuilder.test.ts b/packages/browser/test/eventbuilder.test.ts index ef233ed58a1f..02830f2bd20b 100644 --- a/packages/browser/test/eventbuilder.test.ts +++ b/packages/browser/test/eventbuilder.test.ts @@ -168,6 +168,81 @@ describe('eventFromUnknownInput', () => { }, }); }); + + it('add a synthetic stack trace to DOMException with empty stack traces if attachStacktrace is true', async () => { + const exception = new DOMException('The string did not match the expected pattern.', 'SyntaxError'); + exception.stack = ''; + + const syntheticException = new Error('Test message'); + const event = await eventFromUnknownInput(defaultStackParser, exception, syntheticException, true); + expect(event.exception?.values?.[0]).toEqual( + expect.objectContaining({ + mechanism: { handled: true, synthetic: true, type: 'generic' }, + stacktrace: { + frames: expect.arrayContaining([expect.any(Object), expect.any(Object)]), + }, + type: 'Error', + value: 'SyntaxError: The string did not match the expected pattern.', + }), + ); + }); + + it('add a synthetic stack trace to DOMException without a stack traces property if attachStacktrace is true', async () => { + const exception = new DOMException('The string did not match the expected pattern.', 'SyntaxError'); + delete exception.stack; + + const syntheticException = new Error('Test message'); + const event = await eventFromUnknownInput(defaultStackParser, exception, syntheticException, true); + expect(event.exception?.values?.[0]).toEqual( + expect.objectContaining({ + mechanism: { handled: true, synthetic: true, type: 'generic' }, + stacktrace: { + frames: expect.arrayContaining([expect.any(Object), expect.any(Object)]), + }, + type: 'Error', + value: 'SyntaxError: The string did not match the expected pattern.', + }), + ); + }); + + it("doesn't add a synthetic stack trace to DOMException with empty stack traces if attachStacktrace is false", async () => { + const exception = new DOMException('The string did not match the expected pattern.', 'SyntaxError'); + exception.stack = ''; + + const syntheticException = new Error('Test message'); + const event = await eventFromUnknownInput(defaultStackParser, exception, syntheticException, false); + expect(event.exception?.values?.[0]).toEqual( + { + type: 'Error', + value: 'SyntaxError: The string did not match the expected pattern.', + }, + ); + }); + + it("doesn't add a synthetic stack trace to DOMException with stack traces if attachStacktrace is true", async () => { + const exception = new DOMException('The string did not match the expected pattern.', 'SyntaxError'); + exception.stack = 'SyntaxError\n at :1:2'; + + const syntheticException = new Error('Test message'); + const event = await eventFromUnknownInput(defaultStackParser, exception, syntheticException, true); + expect(event.exception?.values?.[0]).toEqual( + expect.objectContaining({ + stacktrace: { + frames: [ + { + colno: 2, + filename: "", + function: "?", + in_app: true, + lineno: 1, + }, + ], + }, + type: 'SyntaxError', + value: 'The string did not match the expected pattern.', + }), + ); + }); }); describe('extractMessage', () => { From 8cb32a48f7495fc234a18ca0ba82de24b6d372e4 Mon Sep 17 00:00:00 2001 From: abcang Date: Tue, 31 Mar 2026 21:59:02 +0900 Subject: [PATCH 2/2] Run yarn format --- packages/browser/test/eventbuilder.test.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/browser/test/eventbuilder.test.ts b/packages/browser/test/eventbuilder.test.ts index 02830f2bd20b..d73462f73899 100644 --- a/packages/browser/test/eventbuilder.test.ts +++ b/packages/browser/test/eventbuilder.test.ts @@ -211,12 +211,10 @@ describe('eventFromUnknownInput', () => { const syntheticException = new Error('Test message'); const event = await eventFromUnknownInput(defaultStackParser, exception, syntheticException, false); - expect(event.exception?.values?.[0]).toEqual( - { - type: 'Error', - value: 'SyntaxError: The string did not match the expected pattern.', - }, - ); + expect(event.exception?.values?.[0]).toEqual({ + type: 'Error', + value: 'SyntaxError: The string did not match the expected pattern.', + }); }); it("doesn't add a synthetic stack trace to DOMException with stack traces if attachStacktrace is true", async () => { @@ -231,8 +229,8 @@ describe('eventFromUnknownInput', () => { frames: [ { colno: 2, - filename: "", - function: "?", + filename: '', + function: '?', in_app: true, lineno: 1, },