getsentry / sentry-javascript

Official Sentry SDKs for JavaScript
https://sentry.io
MIT License
7.95k stars 1.57k forks source link

ErrorBoundary not marking errors as handled when they come from a jotai atom fetch call #14051

Open wcardosodev opened 7 hours ago

wcardosodev commented 7 hours ago

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/react

SDK Version

7.119.1

Framework Version

18.2.0

Link to Sentry event

https://statsbomb.sentry.io/issues/5999056924/?environment=development&project=4506507098062848&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D&referrer=issue-stream&statsPeriod=1h&stream_index=0

Reproduction Example/SDK Setup

  Sentry.init({
    debug: !!Number(env.VITE_SENTRY_DEBUG),
    dsn: env.VITE_SENTRY_DSN,
    environment,
    integrations: [
      // https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/
      new Sentry.BrowserTracing({
        routingInstrumentation: Sentry.reactRouterV6Instrumentation(
          React.useEffect,
          useLocation,
          useNavigationType,
          createRoutesFromChildren,
          matchRoutes,
        ),
      }),
      new Sentry.Breadcrumbs(),
      new Sentry.HttpContext(),
    ],
    // Performance Monitoring
    tracesSampleRate: 1.0, //  Capture 100% of the transactions
  });

Steps to Reproduce

We are using jotai and if we make a query using atomWithQuery or atomWithSuspenseQuery and the response is bad, we throw an error i.e:

// fetch function
const fetch = () => {
    const response = await window.fetch(`someEndpoint`)

    if (!response.ok) {
      span?.setStatus('unknown_error');
      throw new Error(`Fetch error: ${response.status} at ${input}`);
    }
    else {
   return response;
}
}

// query atom
export const userDetailsAtom = atomWithSuspenseQuery(get => {
  const queryKey = ['user'] as const;
  const queryFn = async () => {
    const { fetch } = get(fetchClientAtom);
    const response = await fetch(`/user-details`);
    return response as UserDetails;
  };
  return { queryKey, queryFn };
});

The problem here is that errors thrown from the fetch don't get marked as handled by sentry, even though the component they get called from are wrapped with an ErrorBoundary with a fallback like:

// component
const Component = ({ children }: { children: React.ReactNode }) => {
  const response = useAtomValue(userDetailsAtom);

  return response.data;
};

// wrapper
<ErrorBoundary fallback={<div>Some fallback test</div>}>
   <Component>{children}</ShowErrorWithData>
 </ErrorBoundary>

Instead these get marked as unhandled, whereas if you did something similar but threw the error just inside the component (rather than in the fetch itself) it would be marked as handled i.e

// component
const Component = ({ children }: { children: React.ReactNode }) => {
  const response = useAtomValue(userDetailsAtom);
  if (response === "bad") throw new Error("Show Error")
  return response.data;
};

// wrapper
<ErrorBoundary fallback={<div>Some fallback test</div>}>
   <Component>{children}</ShowErrorWithData>
 </ErrorBoundary>

Which you can see here being marked as handled: https://statsbomb.sentry.io/issues/6011758573/?environment=development&project=4506507098062848&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D&referrer=issue-stream&statsPeriod=1h&stream_index=1

Expected Result

Expected behaviour is that the error gets marked as handled as it's happening within a component being wrapped by an ErrorBoundary.

Actual Result

The error is not being marked as handled

s1gr1d commented 7 hours ago

Hello and thanks for reaching out! How does your ErrorBoundary component look like? It would be awesome if you could provide us with a minimal reproduction example so we can have a better look at it and are able to define the exact problem.