From 8e78e6e5ec3b5894176555ee4e19b3368d64c969 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 22 Mar 2023 16:38:09 +0100 Subject: [PATCH] fix(react): Handle case where error.cause already defined (#7557) If `error.cause` is already defined, attempt to walk down the error chain to set the `ReactErrorBoundary` error. --- packages/react/src/errorboundary.tsx | 21 ++++- packages/react/test/errorboundary.test.tsx | 101 +++++++++++++++++++-- 2 files changed, 111 insertions(+), 11 deletions(-) diff --git a/packages/react/src/errorboundary.tsx b/packages/react/src/errorboundary.tsx index 1553028195a2..96a88cf31e73 100644 --- a/packages/react/src/errorboundary.tsx +++ b/packages/react/src/errorboundary.tsx @@ -66,6 +66,25 @@ const INITIAL_STATE = { eventId: null, }; +function setCause(error: Error & { cause?: Error }, cause: Error): void { + const seenErrors = new WeakMap(); + + function recurse(error: Error & { cause?: Error }, cause: Error): void { + // If we've already seen the error, there is a recursive loop somewhere in the error's + // cause chain. Let's just bail out then to prevent a stack overflow. + if (seenErrors.has(error)) { + return; + } + if (error.cause) { + seenErrors.set(error, true); + return recurse(error.cause, cause); + } + error.cause = cause; + } + + recurse(error, cause); +} + /** * A ErrorBoundary component that logs errors to Sentry. Requires React >= 16. * NOTE: If you are a Sentry user, and you are seeing this stack frame, it means the @@ -93,7 +112,7 @@ class ErrorBoundary extends React.Component; } -const TestApp: React.FC = ({ children, ...props }) => { +interface TestAppProps extends ErrorBoundaryProps { + errorComp?: JSX.Element; +} + +const TestApp: React.FC = ({ children, errorComp, ...props }) => { + // eslint-disable-next-line no-param-reassign + const customErrorComp = errorComp || ; const [isError, setError] = React.useState(false); return ( = ({ children, ...props }) => { } }} > - {isError ? : children} + {isError ? customErrorComp : children}