From 8df4478e40208fcbaa6d83aa33631eecf8b36430 Mon Sep 17 00:00:00 2001 From: "posthog-eu[bot]" <226701856+posthog-eu[bot]@users.noreply.github.com> Date: Sat, 12 Sep 2026 03:02:43 +0000 Subject: [PATCH] Fix: Drop opaque cross-origin "Script error." events Drop stackless "Script error." exceptions in the observability before_send hook so cross-origin script failures from extensions or third-party scripts stop reaching error tracking as high-severity, unactionable noise. Add crossorigin="anonymous" to the Cloudflare Turnstile script tag so a real Turnstile load failure reports a usable stack instead of the same opaque message. Generated-By: PostHog Desktop Task-Id: 87554b1b-8413-4f2c-8818-969ae09248db --- apps/project/src/components/Turnstile.tsx | 3 +++ packages/observability/src/initAnalytics.ts | 27 ++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/apps/project/src/components/Turnstile.tsx b/apps/project/src/components/Turnstile.tsx index 809baa4d..e075f860 100644 --- a/apps/project/src/components/Turnstile.tsx +++ b/apps/project/src/components/Turnstile.tsx @@ -42,6 +42,9 @@ function loadTurnstileScript(): Promise { script.src = SCRIPT_SRC; script.async = true; script.defer = true; + // Report a real Turnstile load failure with a usable stack instead of an + // opaque cross-origin "Script error.". + script.crossOrigin = "anonymous"; script.onload = () => resolve(); script.onerror = () => reject(new Error("Failed to load Turnstile")); document.head.appendChild(script); diff --git a/packages/observability/src/initAnalytics.ts b/packages/observability/src/initAnalytics.ts index a15f5525..8db43738 100644 --- a/packages/observability/src/initAnalytics.ts +++ b/packages/observability/src/initAnalytics.ts @@ -1,5 +1,5 @@ import { appData } from "@repo/lib"; -import posthog from "posthog-js"; +import posthog, { type CaptureResult } from "posthog-js"; export type AnalyticsSurface = "project" | "remote" | "renderer"; @@ -14,6 +14,27 @@ const isReplayEnabled = (surface: AnalyticsSurface) => ? appData.getAnalyticsRendererReplayEnabled() : appData.getAnalyticsReplayEnabled(); +// A cross-origin script that throws without CORS headers surfaces in the +// browser as an opaque "Script error." with no stack and a synthetic +// mechanism. These come from extensions or third-party scripts, carry no +// stack to debug, and reach error tracking as high-severity noise, so we drop +// them before they leave the browser. +const isOpaqueScriptError = (event: CaptureResult): boolean => { + if (event.event !== "$exception") { + return false; + } + + const exceptionList = event.properties?.$exception_list; + if (!Array.isArray(exceptionList) || exceptionList.length === 0) { + return false; + } + + return exceptionList.every((exception) => { + const frameCount = exception?.stacktrace?.frames?.length ?? 0; + return exception?.value === "Script error." && frameCount === 0; + }); +}; + export const initAnalytics = ({ surface, env }: InitAnalyticsOptions) => { const key = appData.getAnalyticsKey(); @@ -46,6 +67,10 @@ export const initAnalytics = ({ surface, env }: InitAnalyticsOptions) => { return null; } + if (isOpaqueScriptError(event)) { + return null; + } + return { ...event, properties: {