|
| 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