Skip to content

fix(sdk): drop unhandled rejection noise from browser extensions in beforeSend#119463

Draft
billyvg wants to merge 8 commits into
masterfrom
claude/serene-cannon-2vvbwh-frontend
Draft

fix(sdk): drop unhandled rejection noise from browser extensions in beforeSend#119463
billyvg wants to merge 8 commits into
masterfrom
claude/serene-cannon-2vvbwh-frontend

Conversation

@billyvg

@billyvg billyvg commented Jul 11, 2026

Copy link
Copy Markdown
Member

Drop UnhandledRejection events that originate from browser extensions (MetaMask, other crypto-wallet content scripts) — they are third-party noise, never actionable by Sentry engineers.

Problem

Browser extensions like MetaMask fire their own unhandled promise rejections (e.g. error code 4001 — "MetaMask Personal Sign: User denied message signature") into the host page's global unhandledrejection handler. The Sentry SDK captures these and reports them as real issues.

The thirdPartyErrorFilterIntegration is configured with behaviour: 'apply-tag-if-contains-third-party-frames', which only tags events — it does not drop them. So these extension events make it all the way to Sentry.

Characteristics of the noise:

  • mechanism.type === 'auto.browser.global_handlers.onunhandledrejection'
  • originalException is a plain object (not an Error) with a .stack property pointing at chrome-extension:// or moz-extension://
  • No frames from Sentry's own code; entirely third-party

Fix

Add isBrowserExtensionError(event, hint) and call it in beforeSend. It returns true (→ null → dropped) when:

  1. The exception mechanism is onunhandledrejection
  2. hint.originalException is a non-Error plain object with a .stack string containing chrome-extension:// or moz-extension://

This is intentionally narrow: it only drops events where the original rejection value itself points at an extension, not events where an extension merely appears somewhere in the stack of a real Error.

Evidence

Triggered by an alert for event 0a22da40441f40ba85512dfdf107649b on the /explore/traces/ page. Full stack trace was:

Error: MetaMask Personal Sign: User denied message signature.
  at chrome-extension://acmacodkjbdgmoleebolmdjonilkdbch/content-script.js

No Sentry frames. The rejection value was {code: 4001, message: "...", stack: "...chrome-extension://..."} — a plain object, not an Error.

Session

https://claude.ai/code/session_015Gd856MCZWtWz8VmqLdaA3

Legal Boilerplate

Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms.


Generated by Claude Code

manessaraj and others added 8 commits July 8, 2026 13:46
Simplify the logic a bit
Simplify the logic a bit
Add a deterministic, local conversion from "humanized" ESQ, i.e. the shape
filter chips already render in ("is unresolved assigned is me"), back
to real ESQ ("is:unresolved assigned:me"), surfaced as one suggestion in
the search bar's free-text dropdown.
This reverts commit aaaed59.
MetaMask and other crypto-wallet Chrome extensions propagate their own
unhandled rejections (e.g. error code 4001 "User Rejected Request") into
the host page's global unhandledrejection handler. These arrive as plain
objects (not Error instances) with a stack trace pointing at a
chrome-extension:// or moz-extension:// URL and are never actionable by
Sentry engineers.

Add isBrowserExtensionError() to beforeSend that returns null for these
events, keyed on:
1. mechanism type auto.browser.global_handlers.onunhandledrejection
2. originalException is a non-Error plain object whose .stack contains
   chrome-extension:// or moz-extension://

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Jul 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📊 Type Coverage Diff

Metric Before After Delta
Coverage 93.93% 93.93% ±0%
Typed 134,708 134,754 🟢 +46
Untyped 8,704 8,707 🔴 +3
🔍 3 new type safety issues introduced

Non-null assertions (!) (1 new)

File Line Detail
static/app/components/searchQueryBuilder/askSeerCombobox/humanizedToEsq.ts 57 words[i]!

Type assertions (as) (2 new)

File Line Detail
static/app/bootstrap/initializeSdk.tsx 296 as Record<string, unknown>originalException as Record<string, unknown>
static/app/bootstrap/initializeSdk.tsx 298 as {stack: string}originalException as {stack: string}

This is informational only and does not block the PR.

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

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants