From a63ffea0e26dcd440761e677443041b30c26ac75 Mon Sep 17 00:00:00 2001
From: 4ktluffy
Date: Mon, 19 Oct 2026 22:18:24 +0300
Subject: [PATCH] fix(react): Don't crash ErrorBoundary when `error.cause` is
not an Error
---
packages/react/src/error.ts | 4 ++++
packages/react/test/errorboundary.test.tsx | 22 ++++++++++++++++++++++
2 files changed, 26 insertions(+)
diff --git a/packages/react/src/error.ts b/packages/react/src/error.ts
index e290a2baf4c9..9656f1497da9 100644
--- a/packages/react/src/error.ts
+++ b/packages/react/src/error.ts
@@ -15,6 +15,10 @@ export function setCause(error: Error & { cause?: Error }, cause: Error): void {
return;
}
if (error.cause) {
+ // We can only link to an `Error` cause, not e.g. a string (`new Error('x', { cause: 'y' })`).
+ if (!isError(error.cause)) {
+ return;
+ }
seenErrors.add(error);
return recurse(error.cause, cause);
}
diff --git a/packages/react/test/errorboundary.test.tsx b/packages/react/test/errorboundary.test.tsx
index 7e0a8fe42e37..86db01177cc8 100644
--- a/packages/react/test/errorboundary.test.tsx
+++ b/packages/react/test/errorboundary.test.tsx
@@ -489,6 +489,28 @@ describe('ErrorBoundary', () => {
expect(cause.message).toEqual(thirdError.message);
});
+ it('handles when `error.cause` is not an Error', () => {
+ function CustomBam(): JSX.Element {
+ const error = new Error('bam');
+ // @ts-expect-error Need to set cause on error
+ error.cause = 'timeout';
+ throw error;
+ }
+
+ const { container } = render(
+ You have hit an error
} errorComp={}>
+ children
+ ,
+ );
+
+ const btn = screen.getByTestId('errorBtn');
+ fireEvent.click(btn);
+
+ expect(container.innerHTML).toContain('You have hit an error');
+ expect(mockCaptureException).toHaveBeenCalledTimes(1);
+ expect(mockCaptureException.mock.calls[0]?.[0].cause).toBe('timeout');
+ });
+
it('handles when `error.cause` is recursive', () => {
const mockOnError = vi.fn();