From ec98cca9d4dde9cdc387889d9cb50269b4ec9a2a Mon Sep 17 00:00:00 2001 From: Shabnam Date: Tue, 23 Jun 2026 22:44:22 +0400 Subject: [PATCH] fix(sentry): re-register inboundFiltersIntegration so ignoreErrors runs (#3970) --- app/src/services/__tests__/analytics.test.ts | 29 ++++++++++++++++++++ app/src/services/analytics.ts | 8 ++++++ 2 files changed, 37 insertions(+) diff --git a/app/src/services/__tests__/analytics.test.ts b/app/src/services/__tests__/analytics.test.ts index 6bda3c342..ddc3b9357 100644 --- a/app/src/services/__tests__/analytics.test.ts +++ b/app/src/services/__tests__/analytics.test.ts @@ -10,6 +10,7 @@ const hoisted = vi.hoisted(() => ({ init: vi.fn(), // Integration stubs — these aren't introspected, just need to exist so // `Sentry.init()` accepts the integrations array without throwing. + inboundFiltersIntegration: vi.fn(() => ({ name: 'InboundFilters' })), functionToStringIntegration: vi.fn(() => ({})), linkedErrorsIntegration: vi.fn(() => ({})), dedupeIntegration: vi.fn(() => ({})), @@ -29,6 +30,7 @@ vi.mock('@sentry/react', () => ({ captureMessage: hoisted.captureMessage, flush: hoisted.flush, init: hoisted.init, + inboundFiltersIntegration: hoisted.inboundFiltersIntegration, functionToStringIntegration: hoisted.functionToStringIntegration, linkedErrorsIntegration: hoisted.linkedErrorsIntegration, dedupeIntegration: hoisted.dedupeIntegration, @@ -308,6 +310,33 @@ describe('initSentry beforeSend manual-staging bypass', () => { expect(names).toContain('HttpContext'); }); + test('registers inboundFiltersIntegration so ignoreErrors is not inert (#3963)', async () => { + // Regression for #3963: `defaultIntegrations: false` drops the integration + // that consumes the top-level `ignoreErrors` option. The curated list must + // re-include `inboundFiltersIntegration`, otherwise the intended + // `ResizeObserver loop` / network-noise filters silently leak to Sentry. + // Asserting both the integration AND the non-empty filter list guards the + // coupling — dropping either re-opens the flood. + hoisted.init.mockReset(); + hoisted.inboundFiltersIntegration.mockClear(); + const { initSentry } = await import('../analytics'); + initSentry(); + + const opts = hoisted.init.mock.calls[0][0] as { + integrations: Array<{ name?: string }>; + ignoreErrors: string[]; + }; + expect(hoisted.inboundFiltersIntegration).toHaveBeenCalledTimes(1); + const names = opts.integrations.map(i => i.name).filter(Boolean); + expect(names).toContain('InboundFilters'); + expect(opts.ignoreErrors).toEqual([ + 'ResizeObserver loop', + 'Network request failed', + 'Load failed', + 'AbortError', + ]); + }); + test('keeps os/browser/device contexts and forwards them through beforeSend (#1403)', async () => { hoisted.analyticsEnabled = true; // consent on so beforeSend doesn't drop. const beforeSend = await captureBeforeSend(); diff --git a/app/src/services/analytics.ts b/app/src/services/analytics.ts index 8cfe84a24..67c3e7fec 100644 --- a/app/src/services/analytics.ts +++ b/app/src/services/analytics.ts @@ -147,6 +147,14 @@ export function initSentry(): void { tracesSampleRate: 0, defaultIntegrations: false, integrations: [ + // #3963: `defaultIntegrations: false` (above) drops the integration that + // consumes the top-level `ignoreErrors` option (below), so the intended + // noise filter has been dead config since it was added. Re-include it + // explicitly so `ignoreErrors` runs again. It executes as an event + // processor *before* `beforeSend`, so the consent/privacy logic there is + // unaffected — this only restores the pre-`beforeSend` drop of the four + // benign `ResizeObserver loop` / network-noise patterns. + Sentry.inboundFiltersIntegration(), Sentry.functionToStringIntegration(), Sentry.linkedErrorsIntegration(), Sentry.dedupeIntegration(),