diff --git a/instrumentation-client.ts b/instrumentation-client.ts index 3644fbe0..7e74b642 100644 --- a/instrumentation-client.ts +++ b/instrumentation-client.ts @@ -37,6 +37,13 @@ if (dsn) { // 投げる (throw new Error(...)) ため、実シグナルの取りこぼしリスクは実質ゼロ。 ignoreErrors: [ /Non-Error promise rejection captured/, + // 同族の兄弟パターン: 拒否理由が DOM Event のとき Sentry は上とは別の文言 + // 「Event `Event` (type=error) captured as promise rejection」を生成し、上の + // フィルタをすり抜ける (2026-08-18 mainnet 実観測: 存在しない /en/faq への + // 旧 UA Chrome 123 アクセスの 404 上・スタックなし・非アクショナブル)。 + // script/リソース読込失敗の promise 化やウォレット拡張が典型で、自前コードは + // Error 以外で reject しないため実シグナルは落ちない。 + /captured as promise rejection/, // ウォレット拡張/SDK の接続・再接続失敗 (MetaMask 等)。ページ読込時の自動再接続 // (wagmi reconnectOnMount=true) や、ロック中/権限未付与/接続キャンセルのウォレットで // 日常的に発生する。スタックはウォレット拡張内 (chrome-extension://…/inpage.js) を指し diff --git a/tests/instrumentation-client.test.ts b/tests/instrumentation-client.test.ts index cb05e0f4..30b9da6f 100644 --- a/tests/instrumentation-client.test.ts +++ b/tests/instrumentation-client.test.ts @@ -15,6 +15,25 @@ describe('instrumentation-client telemetry hooks', () => { sentry.replayIntegration.mockClear(); }); + it('ignoreErrors が non-Error 拒否の両文言 (value 形式 / DOM Event 形式) を落とす', async () => { + await import('@/instrumentation-client'); + const options = sentry.init.mock.calls[0][0] as { + ignoreErrors: RegExp[]; + }; + const matches = (msg: string) => + options.ignoreErrors.some((re) => re.test(msg)); + // 既存: 値付きの non-Error 拒否 + expect( + matches('Non-Error promise rejection captured with value: undefined'), + ).toBe(true); + // 2026-08-18 実観測の兄弟パターン: DOM Event が拒否理由のときの別文言 + expect( + matches('Event `Event` (type=error) captured as promise rejection'), + ).toBe(true); + // 実シグナル (自前 Error) は落とさない + expect(matches('Error: relay settle failed')).toBe(false); + }); + it('beforeBreadcrumb / beforeSendTransaction に URL scrubber を設定する', async () => { await import('@/instrumentation-client');