fix(sentry): ignore postMessage clone noise (#373)

## Summary
- filter browser postMessage DataCloneError noise before Sentry send
- add focused classifier tests

## Tests
- npm test -- resources/js/lib/sentry.test.ts
- npm run types *(fails: existing repo-wide TypeScript errors, including
missing Wayfinder generated modules)*

Fixes PHP-LARAVEL-1M
This commit is contained in:
Víctor Falcón 2026-05-10 11:16:38 +01:00 committed by GitHub
parent 718cfa9e8f
commit 6335287765
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 81 additions and 0 deletions

View File

@ -20,6 +20,7 @@ import { SyncProvider } from './contexts/sync-context';
import { initializeTheme } from './hooks/use-appearance';
import { initializeChartColorScheme } from './hooks/use-chart-color-scheme';
import { initializePostHog } from './lib/posthog';
import { isPostMessageDataCloneNoise } from './lib/sentry';
import type { SharedData } from './types';
import { setTranslations } from './utils/i18n';
@ -29,6 +30,13 @@ Sentry.init({
integrations: [],
tracesSampleRate: 0,
sendDefaultPii: true,
beforeSend(event) {
if (isPostMessageDataCloneNoise(event)) {
return null;
}
return event;
},
enabled:
import.meta.env.PROD && Boolean(import.meta.env.SENTRY_LARAVEL_DSN),
});

View File

@ -0,0 +1,49 @@
import type { Event } from '@sentry/react';
import { describe, expect, it } from 'vitest';
import { isPostMessageDataCloneNoise } from './sentry';
describe('isPostMessageDataCloneNoise', () => {
it('drops browser postMessage DataCloneError noise', () => {
const event: Event = {
exception: {
values: [
{
type: 'DataCloneError',
value: 'The object can not be cloned.',
stacktrace: {
frames: [
{
function: 'Window.postMessage',
},
],
},
},
],
},
};
expect(isPostMessageDataCloneNoise(event)).toBe(true);
});
it('keeps other DataCloneError events without postMessage frames', () => {
const event: Event = {
exception: {
values: [
{
type: 'DataCloneError',
value: 'The object can not be cloned.',
stacktrace: {
frames: [
{
function: 'structuredClone',
},
],
},
},
],
},
};
expect(isPostMessageDataCloneNoise(event)).toBe(false);
});
});

View File

@ -0,0 +1,24 @@
import type { Event } from '@sentry/react';
const CLONE_ERROR_MESSAGE_PATTERN =
/object (can not|could not|couldn't|can't) be cloned/i;
export function isPostMessageDataCloneNoise(event: Event): boolean {
return (
event.exception?.values?.some((exception) => {
const exceptionType = exception.type ?? '';
const exceptionValue = exception.value ?? '';
const frames = exception.stacktrace?.frames ?? [];
return (
exceptionType === 'DataCloneError' &&
CLONE_ERROR_MESSAGE_PATTERN.test(exceptionValue) &&
frames.some((frame) =>
[frame.function, frame.filename, frame.module].some(
(value) => value?.includes('postMessage'),
),
)
);
}) ?? false
);
}