Skip to content

Commit 89d1a79

Browse files
fix(react): Remove unused react.componentStack event context
The `react.componentStack` event context set by `captureReactException` on every captured error never gets sourcemaps applied, so the string it ships is mostly unreadable. For React >= 17 the same component stack is already attached via `error.cause` (which does get sourcemaps); for React < 17 it offers little value either. Drop the `setContext('react', ...)` call. The surrounding `withScope` wrapper has no other mutation, so collapse it to a direct `captureException` call and drop the now-unused `withScope` import. Sync the spy assertions in `errorboundary.test.tsx`: remove the `scopeSetContextSpy` setup and rewrite the `cause.stack`-versus-mock expectations to `expect.any(String)` — the strongest invariant we can still observe once the spy is gone, since the underlying `setCause` / `errorBoundaryError.stack = componentStack` chain is unchanged. The negation case in the recursive-cause test collapses into the existing `cause.name` assertion, with an inline comment explaining why the original (non-ErrorBoundary) cause is preserved when the chain loops. Closes #20094 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent ed0c4cf commit 89d1a79

2 files changed

Lines changed: 8 additions & 24 deletions

File tree

packages/react/src/error.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { captureException, withScope } from '@sentry/browser';
1+
import { captureException } from '@sentry/browser';
22
import { isError } from '@sentry/core/browser';
33
import type { ErrorInfo } from 'react';
44
import { version } from 'react';
@@ -64,10 +64,7 @@ export function captureReactException(
6464
setCause(error, errorBoundaryError);
6565
}
6666

67-
return withScope(scope => {
68-
scope.setContext('react', { componentStack });
69-
return captureException(error, hint);
70-
});
67+
return captureException(error, hint);
7168
}
7269

7370
/**

packages/react/test/errorboundary.test.tsx

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import type { ErrorBoundaryProps, FallbackRender } from '../src/errorboundary';
1111
import { ErrorBoundary, UNKNOWN_COMPONENT, withErrorBoundary } from '../src/errorboundary';
1212

1313
const mockScope = new Scope();
14-
const scopeSetContextSpy = vi.spyOn(mockScope, 'setContext');
1514
const mockCaptureException = vi.fn();
1615
const mockShowReportDialog = vi.fn();
1716
const mockClientOn = vi.fn();
@@ -388,16 +387,13 @@ describe('ErrorBoundary', () => {
388387
mechanism: { handled: true, type: 'auto.function.react.error_boundary' },
389388
});
390389

391-
expect(scopeSetContextSpy).toHaveBeenCalledTimes(1);
392-
expect(scopeSetContextSpy).toHaveBeenCalledWith('react', { componentStack: expect.any(String) });
393-
394390
expect(mockOnError.mock.calls[0]?.[0]).toEqual(mockCaptureException.mock.calls[0]?.[0]);
395391

396392
// Check if error.cause -> react component stack
397393
const error = mockCaptureException.mock.calls[0]?.[0];
398394
const cause = error.cause;
399395

400-
expect(cause.stack).toEqual(scopeSetContextSpy.mock.calls[0]?.[1]?.componentStack);
396+
expect(cause.stack).toEqual(expect.any(String));
401397
expect(cause.name).toContain('React ErrorBoundary');
402398
expect(cause.message).toEqual(error.message);
403399
});
@@ -447,9 +443,6 @@ describe('ErrorBoundary', () => {
447443
mechanism: { handled: true, type: 'auto.function.react.error_boundary' },
448444
});
449445

450-
expect(scopeSetContextSpy).toHaveBeenCalledTimes(1);
451-
expect(scopeSetContextSpy).toHaveBeenCalledWith('react', { componentStack: expect.any(String) });
452-
453446
// Check if error.cause -> react component stack
454447
const error = mockCaptureException.mock.calls[0]?.[0];
455448
expect(error.cause).not.toBeDefined();
@@ -486,16 +479,13 @@ describe('ErrorBoundary', () => {
486479
mechanism: { handled: true, type: 'auto.function.react.error_boundary' },
487480
});
488481

489-
expect(scopeSetContextSpy).toHaveBeenCalledTimes(1);
490-
expect(scopeSetContextSpy).toHaveBeenCalledWith('react', { componentStack: expect.any(String) });
491-
492482
expect(mockOnError.mock.calls[0]?.[0]).toEqual(mockCaptureException.mock.calls[0]?.[0]);
493483

494484
const thirdError = mockCaptureException.mock.calls[0]?.[0];
495485
const secondError = thirdError.cause;
496486
const firstError = secondError.cause;
497487
const cause = firstError.cause;
498-
expect(cause.stack).toEqual(scopeSetContextSpy.mock.calls[0]?.[1]?.componentStack);
488+
expect(cause.stack).toEqual(expect.any(String));
499489
expect(cause.name).toContain('React ErrorBoundary');
500490
expect(cause.message).toEqual(thirdError.message);
501491
});
@@ -530,15 +520,14 @@ describe('ErrorBoundary', () => {
530520
mechanism: { handled: true, type: 'auto.function.react.error_boundary' },
531521
});
532522

533-
expect(scopeSetContextSpy).toHaveBeenCalledTimes(1);
534-
expect(scopeSetContextSpy).toHaveBeenCalledWith('react', { componentStack: expect.any(String) });
535-
536523
expect(mockOnError.mock.calls[0]?.[0]).toEqual(mockCaptureException.mock.calls[0]?.[0]);
537524

538525
const error = mockCaptureException.mock.calls[0]?.[0];
539526
const cause = error.cause;
540-
// We need to make sure that recursive error.cause does not cause infinite loop
541-
expect(cause.stack).not.toEqual(scopeSetContextSpy.mock.calls[0]?.[1]?.componentStack);
527+
// We need to make sure that recursive error.cause does not cause infinite loop:
528+
// when the cause chain loops, captureReactException bails out of setCause and
529+
// leaves the original (non-ErrorBoundary) cause intact instead of overwriting
530+
// it with `errorBoundaryError`.
542531
expect(cause.name).not.toContain('React ErrorBoundary');
543532
});
544533

@@ -698,8 +687,6 @@ describe('ErrorBoundary', () => {
698687
mechanism: { handled: expected, type: 'auto.function.react.error_boundary' },
699688
});
700689

701-
expect(scopeSetContextSpy).toHaveBeenCalledTimes(1);
702-
expect(scopeSetContextSpy).toHaveBeenCalledWith('react', { componentStack: expect.any(String) });
703690
},
704691
);
705692
});

0 commit comments

Comments
 (0)