Skip to content

Commit 0733461

Browse files
authored
Filter noisy wallet/extension errors in Sentry (#2928)
1 parent add529e commit 0733461

2 files changed

Lines changed: 104 additions & 0 deletions

File tree

sentry.client.config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import * as Sentry from '@sentry/nextjs';
77

8+
import { shouldIgnoreError } from './src/utils/sentryFilters';
9+
810
Sentry.init({
911
dsn: 'https://f4f62da759bfe365562d0dfe080a255e@o4508407151525888.ingest.de.sentry.io/4510516896530512',
1012

@@ -14,4 +16,9 @@ Sentry.init({
1416
// Enable sending user PII (Personally Identifiable Information)
1517
// https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii
1618
sendDefaultPii: false,
19+
20+
beforeSend(event) {
21+
if (shouldIgnoreError(event)) return null;
22+
return event;
23+
},
1724
});

src/utils/sentryFilters.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import type { Event } from '@sentry/types';
2+
3+
// Error message patterns to drop. Each regex is tested against
4+
// the first exception value (or the top-level message).
5+
const IGNORED_ERROR_PATTERNS: RegExp[] = [
6+
// Browser-extension subscription/port noise
7+
/connection interrupted while trying to subscribe/i,
8+
/attempting to use a disconnected port object/i,
9+
/the source .+ has not been authorized yet/i,
10+
11+
// MetaMask / wallet connect failures
12+
/failed to connect to metamask/i,
13+
/chrome\.runtime\.sendmessage\(\) called from a webpage must specify an extension id/i,
14+
/cannot read properties of undefined \(reading 'sendmessage'\)/i,
15+
/cannot read properties of undefined \(reading 'networkversion'\)/i,
16+
/cannot read properties of undefined \(reading 'removelistener'\)/i,
17+
/cannot read properties of undefined \(reading 'ton'\)/i,
18+
19+
// Wallet injector conflicts (window.ethereum property fights)
20+
/invalid property descriptor\. cannot both specify accessors and a value or writable attribute/i,
21+
/cannot set property ethereum of #<window> which has only a getter/i,
22+
23+
// Specific wallet extensions
24+
/talisman extension has not been configured yet/i,
25+
/'set' on proxy: trap returned falsish for property 'tronlinkparams'/i,
26+
/bitvisionweb is not defined/i,
27+
/shouldsetpelagusforcurrentprovider is not a function/i,
28+
/the request by this web3 provider is timeout/i,
29+
30+
// wagmi / RainbowKit connector noise
31+
/providernotfounderror: provider not found/i,
32+
/connectornotconnectederror: connector not connected/i,
33+
34+
// Cross-origin frame (wallet iframes)
35+
/blocked a frame with origin .+ from accessing a cross-origin frame/i,
36+
37+
// WalletConnect
38+
/websocket connection closed abnormally with code: 3000/i,
39+
/websocket connection failed for host: wss:\/\/relay\.walletconnect\.org/i,
40+
/no matching key\. session topic doesn't exist/i,
41+
/walletconnect.+proposal expired/i,
42+
/request expired\. please try again/i,
43+
/failed to execute 'transaction' on 'idbdatabase': the database connection is closing/i,
44+
45+
// User rejections (wallet-specific patterns)
46+
/userrejectedrequesterror/i,
47+
/user rejected the request/i,
48+
/user rejected transaction/i,
49+
/user denied transaction signature/i,
50+
/user denied message signature/i,
51+
52+
// Contract revert with no reason string (not actionable from frontend)
53+
/missing revert data in call exception/i,
54+
55+
// Non-Error null rejections (wallet/provider teardown)
56+
/non-error promise rejection captured with value: null/i,
57+
58+
// Network / browser noise
59+
/can't find variable: eip155/i,
60+
];
61+
62+
// Culprit / stack-frame patterns. These catch errors that have generic
63+
// messages (e.g. "Failed to fetch") but originate from injected scripts.
64+
const IGNORED_CULPRIT_PATTERNS: RegExp[] = [
65+
/injectLeap/i,
66+
/inject\.chrome/i,
67+
/extensionServiceWorker/i,
68+
/injectedScript\.bundle/i,
69+
/window-provider/i,
70+
/injected\/injected/i,
71+
/frame_ant\/frame_ant/i,
72+
/\/inpage$/i,
73+
/\/inject$/i,
74+
/\/injector$/i,
75+
/\/btc$/i,
76+
/\/sui$/i,
77+
/\/solana$/i,
78+
];
79+
80+
export function shouldIgnoreError(event: Event): boolean {
81+
const message = event.exception?.values?.[0]?.value ?? event.message ?? '';
82+
const culprit = (event as Record<string, unknown>).culprit as string | undefined;
83+
const frames = event.exception?.values?.[0]?.stacktrace?.frames ?? [];
84+
const topFilename = frames.length > 0 ? frames[frames.length - 1]?.filename : undefined;
85+
86+
// Unconditional message-based filters (safe regardless of source)
87+
if (IGNORED_ERROR_PATTERNS.some((p) => p.test(message))) return true;
88+
89+
const isFromInjectedScript =
90+
(culprit != null && IGNORED_CULPRIT_PATTERNS.some((p) => p.test(culprit))) ||
91+
(topFilename != null && IGNORED_CULPRIT_PATTERNS.some((p) => p.test(topFilename)));
92+
93+
// Drop any error whose stack originates from an injected script
94+
if (isFromInjectedScript) return true;
95+
96+
return false;
97+
}

0 commit comments

Comments
 (0)