From f75adef69fdee7eb1244515d206c32cc4a525c73 Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Thu, 13 Aug 2026 11:56:13 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B(analytics)=20filter=20benign=20Res?= =?UTF-8?q?izeObserver=20loop=20error=20in=20Sentry/PostHog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Filter out harmless `ResizeObserver loop limit exceeded` and `ResizeObserver loop completed with undelivered notifications` errors via `beforeSend`. Why this is safe: * These are W3C spec-mandated browser guards that defer notification delivery to the next frame when callbacks alter layout during render. They do not cause JS runtime exceptions or break the UX. Why we actually need to filter them: * Telemetry platforms like PostHog do not stack/group these well, frequently generating distinct error events per browser engine and version. * The unique variants flood reporting dashboards and trigger false-positive alerts that clutter real issue triage. --- CHANGELOG.md | 1 + .../features/analytics/exceptionFilters.ts | 24 +++++++++++++++++++ .../features/analytics/hooks/useAnalytics.ts | 2 ++ 3 files changed, 27 insertions(+) create mode 100644 src/frontend/src/features/analytics/exceptionFilters.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 36b6ce2b..1078d410 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to - 🐛(frontend) harden speaker test against missing sinks and play errors - 🐛(frontend) implement hysteresis band for the control bar layout - 🐛(frontend) fix toolbar ResizeObserver loop and alignment drift +- 🐛(analytics) filter benign ResizeObserver loop error in Sentry/PostHog ## [1.26.0] - 2026-08-12 diff --git a/src/frontend/src/features/analytics/exceptionFilters.ts b/src/frontend/src/features/analytics/exceptionFilters.ts new file mode 100644 index 00000000..9a11cfe9 --- /dev/null +++ b/src/frontend/src/features/analytics/exceptionFilters.ts @@ -0,0 +1,24 @@ +import type { CaptureResult } from 'posthog-js' + +const IGNORED_EXCEPTION_PATTERNS = [ + /ResizeObserver loop (completed with undelivered notifications|limit exceeded)/, +] + +const shouldIgnoreException = (value: unknown): boolean => + typeof value === 'string' && + IGNORED_EXCEPTION_PATTERNS.some((pattern) => pattern.test(value)) + +export const filterExceptions = ( + event: CaptureResult | null +): CaptureResult | null => { + if (event?.event !== '$exception') return event + + const exceptionList = event.properties?.['$exception_list'] + const values: unknown[] = Array.isArray(exceptionList) + ? exceptionList.map((exception) => exception?.value) + : [] + + values.push(event.properties?.['$exception_message']) + + return values.some(shouldIgnoreException) ? null : event +} diff --git a/src/frontend/src/features/analytics/hooks/useAnalytics.ts b/src/frontend/src/features/analytics/hooks/useAnalytics.ts index a1c2d372..1729bea2 100644 --- a/src/frontend/src/features/analytics/hooks/useAnalytics.ts +++ b/src/frontend/src/features/analytics/hooks/useAnalytics.ts @@ -2,6 +2,7 @@ import { useEffect } from 'react' import { type ApiUser } from '@/features/auth/api/ApiUser' import { useUser } from '@/features/auth/api/useUser' import { getPosthog } from '../utils' +import { filterExceptions } from '../exceptionFilters' export const startAnalyticsSession = (data: ApiUser) => { getPosthog().then((ph) => { @@ -47,6 +48,7 @@ export const useAnalytics = ({ capture_unhandled_rejections: true, capture_console_errors: true, }, + before_send: filterExceptions, }) }) }, [id, host, flags_api_host, isDisabled])