Skip to content

fix(browser): Add a synthetic stack trace to DOMException with empty stack traces if attachStacktrace is true#19988

Open
abcang wants to merge 5 commits into
getsentry:developfrom
abcang:abcang/add_synthetic_stack_trace_to_dom_exception
Open

fix(browser): Add a synthetic stack trace to DOMException with empty stack traces if attachStacktrace is true#19988
abcang wants to merge 5 commits into
getsentry:developfrom
abcang:abcang/add_synthetic_stack_trace_to_dom_exception

Conversation

@abcang
Copy link
Copy Markdown

@abcang abcang commented Mar 26, 2026

DOMException may not always contain a stack trace. Depending on the browser, the stack property might be missing entirely, or it might be set to an empty string.

This PR ensures that empty strings are handled in the same way as missing properties.

For example, when a NotAllowedError occurs during WebAuthn usage, I confirmed that Chrome does not have the stack property, whereas Safari provides it as an empty string.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 26, 2026

Semver Impact of This PR

🟢 Patch (bug fixes)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


Bug Fixes 🐛

  • (browser) Add a synthetic stack trace to DOMException with empty stack traces if attachStacktrace is true by abcang in #19988

Internal Changes 🔧

  • (core) Remove provider-specific AI span attributes in favor of gen_ai attributes in sentry conventions by nicohrubec in #20011

🤖 This preview updates automatically when you update the PR.

Comment thread packages/browser/test/eventbuilder.test.ts Outdated
@abcang abcang force-pushed the abcang/add_synthetic_stack_trace_to_dom_exception branch 3 times, most recently from f16b753 to 0f76c44 Compare March 31, 2026 01:09
Comment thread packages/browser/src/eventbuilder.ts
@abcang abcang force-pushed the abcang/add_synthetic_stack_trace_to_dom_exception branch from 8cb32a4 to c26f7a3 Compare April 17, 2026 01:11
@isaacs
Copy link
Copy Markdown
Member

isaacs commented May 3, 2026

LGTM, thanks! Let's see what the CI robots say :)

@abcang
Copy link
Copy Markdown
Author

abcang commented May 3, 2026

Thank you for triggering the CI! The current failures appear to be unrelated to the changes in this PR.

@andreiborza andreiborza requested a review from a team as a code owner May 12, 2026 09:10
@logaretm logaretm force-pushed the abcang/add_synthetic_stack_trace_to_dom_exception branch from 30ba39c to 83ae1e5 Compare May 12, 2026 16:01
Copy link
Copy Markdown
Member

@logaretm logaretm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

I think this is a good change in general but if the test fails then we should ensure the exception report doesn't change. Let's see.

EDIT: Yep it fails, so I think the change will affect grouping significantly.

// before
"type": "SyntaxError",
"value": "The string did not match the expected pattern.",

// after
"type": "Error",
"value": "SyntaxError: The string did not match the expected pattern.",

const domException = exception as DOMException;

if ('stack' in (exception as Error)) {
if ((exception as Error).stack) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

h: I think this will change how the dom exceptions are classified, I pushed a test to see if it would pass.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like this would keep the best of both worlds here, could you try something like:

// same check as before
if ('stack' in (exception as Error)) {
  event = eventFromError(stackParser, exception as Error);

  // preserves the classification while adding stacktraces if it exists...
  const firstException = event.exception?.values?.[0];
  if (attachStacktrace && syntheticException && firstException && !firstException.stacktrace) {
    const frames = parseStackFrames(stackParser, syntheticException);
    if (frames.length) {
      firstException.stacktrace = { frames };
      addExceptionMechanism(event, { synthetic: true });
    }
  }
} else {
  // existing fallback
}

Comment thread packages/browser/test/eventbuilder.test.ts
value: 'The string did not match the expected pattern.',
},
]);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Contradictory test expects wrong branch behavior

Medium Severity

The test "preserves DOMException type when stack is an empty string" expects type: 'SyntaxError' and value: 'The string did not match the expected pattern.', but it has the same setup as the test at line 172 (stack = '', attachStacktrace = true), which expects type: 'Error' and value: 'SyntaxError: The string did not match the expected pattern.'. Tracing through the production code, the empty stack takes the eventFromString path, producing type: 'Error' and the combined name: message value. This test's expectations reflect the old eventFromError path behavior and will fail.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 83ae1e5. Configure here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works against today's implementation, I'm just ensuring we lock it in and see if this PR changes it.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 901e3ef. Configure here.

const domException = exception as DOMException;

if ('stack' in (exception as Error)) {
if ((exception as Error).stack) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DOMException type classification lost for empty stack traces

Medium Severity

Changing the check from 'stack' in (exception as Error) to a truthy check causes DOMExceptions with empty stack strings to fall into the else branch, which uses eventFromString + addExceptionTypeValue. This loses the specific DOMException type (e.g., 'SyntaxError', 'NotAllowedError') and replaces it with a generic 'Error' type, because addExceptionTypeValue defaults the type to 'Error'. The exception value also changes from just the message to a name: message format. This regression in error classification will affect how users group and identify DOMException errors in Sentry. The contradictory test at line 190 (expecting type: 'SyntaxError') confirms this is a recognized problem — it will fail because the code actually produces type: 'Error'.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 901e3ef. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants