Closed ci-vamp closed 1 year ago
Hey @ci-vamp, thanks for writing in!
I tried reproducing this in a codesandbox: https://codesandbox.io/s/gh-8031-react-captureexception-4xpt5z?file=/src/App.tsx, and I saw able to get this working. Could you provide a reproduction so we can investigate further? Thanks!
debugging this here is what i find:
(root,
index.tsx
,Sentry.captureException
)
(App,
App.tsx
,Sentry.captureException
)
@AbhiPrasad the code sandbox example is not equivalent.
you are using react 18.2 we are on 17.2. could that have an impact?
i tried downgrading to sentry 6.9.x and issue persisted
you can see that in index.tsx
(where Sentry.init
is called) when it reaches the singleton and client for captureException it is fully populated (DSN etc)
however, when it reaches the same point from the call in App.tsx
nothing is populated
you are using react 18.2 we are on 17.2. could that have an impact
It shouldn't have an impact. I updated the codesandbox to use React 17: https://codesandbox.io/s/gh-8031-react-captureexception-4xpt5z?file=/src/index.tsx
however, when it reaches the same point from the call in App.tsx nothing is populated
Ah what might be happening then is that Sentry is not initialized before that code is executed. Basically the imported code runs before Sentry.init
is being called. You can debug this by placing some console.log
statements by the Sentry calls to see execution order.
Make sure that Sentry.init
is being called as early as possible!
@AbhiPrasad
Sentry.init is the first thing in index.tsx
(after imports) which i think is the normal behavior for a react app.
root/ index.tsx <-- imports App, inits Sentry App.tsx <-- imported into index.tsx
i have debugged and am seeing that the index.tsx captureException is indeed firing before the App.tsx captureException, which indicates that the Sentry.init is made before App.tsx capturException is fired
Are you putting the captureException
call in a react component? Or outside of it. What might be happening is that the side effect of the module is being treeshaken away. If you put a console.log
next to the captureException
, does it work?
The best way to debug this is to provide a reproduction, otherwise there's not much more we can do to debug further! Thanks!
i created a callback that wraps Sentry.captureException. i used this in react-error-boundary
as on the onError
callback.
we use this exact setup in our react-native (mobile) project. now trying to integrate sentry into the react (web) project and running into this issue.
it is hitting the captureException and i am able to step through it w the debugger. but what is happening is it is somehow losing its reference to the global Sentry object (or at least its configuration). thats how you can see that the singleton
and client
objects are not populated with DSN etc.
i will try to create a reproduction but the only way i can think of is to cut out all of the code in our codebase but leave the config (webpack etc) the same so its reproducible. cant share all the project code as it is because its closed source
@AbhiPrasad Figured it out!
Turns out that we load a ZenDesk widget which has its own sentry instance. The ZD widget loads in as a global on window and it overwrites our sentry instance / config. This is why everything after the root index was losing its config properties.
I can't find anything online about others having this issue. Do you have any guidance?
The "after return" was after our loading spinner (waiting for user auth to load) is complete. It turns out that the zendesk widget only loads after the user is authed as well!
So at least the problem is defined. But I’m not sure how to proceed. We can't control the ZD widget and their sentry config but of course we need our own.
@ci-vamp which ZD widget are you using?
@HazAT i believe it is the "web widget (classic)" but i can confirm when my teammate gets online
@HazAT yes i can confirm it is the "classic" web widget, here is the documentation
Just to double-check and verify - you run a normal webpage and use the ZD widget in there.
yes we have a react app. in the react app we load in the zendesk widget using their code snippet which we lazy load into the document body. all of this logic (including configuration / auth of the widget) is done through a hook.
from their docs we take the snippet from our admin page and that is what we lazy load in
here is the lazy loading logic in the hook
lazyLoadScript just injects it into the doc body
this is the sentry lib that the ZD widget is loading (note: minified)
@ci-vamp we have some contacts at Zendesk, we're going to reach out to them!
thank you. i am unable to find anyone else having this issue. for the time being i have tried configuring our own client / hub and using that to invoke the captureException
sentryConfig.ts
import * as React from 'react';
import { createRoutesFromChildren, matchRoutes, useLocation, useNavigationType } from 'react-router-dom';
import {
Hub,
BrowserClient,
BrowserTracing,
defaultStackParser,
defaultIntegrations,
makeFetchTransport,
reactRouterV6Instrumentation
} from '@sentry/react';
const sentryClient = new BrowserClient({
debug: true,
transport: makeFetchTransport,
dsn: 'OUR_DSN',
integrations: [
...defaultIntegrations,
new BrowserTracing({
routingInstrumentation: reactRouterV6Instrumentation(
React.useEffect,
useLocation,
useNavigationType,
createRoutesFromChildren,
matchRoutes
)
})
],
stackParser: defaultStackParser,
tracesSampleRate: 1.0,
});
const sentryHub = new Hub(sentryClient);
export default sentryHub;
then in the utility (it accepts additional user / context data which we add to the scope)
// sentryClient is the export from sentryConfig.ts
sentryClient.withScope(scope => {
const scopedUser = scope.getUser();
const user = scopedUser ? { ...scopedUser, ...sentryContext.user } : sentryContext.user;
scope.setUser(user || null);
sentryClient.captureException(error);
})
this seems to work. however when an error is thrown to the error boundary (triggering the utility above as a callback) we get this new error:
ERROR
client.recordDroppedEvent is not a function
TypeError: client.recordDroppedEvent is not a function
at IdleTransaction.finish (https://localhost:3000/static/js/bundle.js:155423:18)
at IdleTransaction.finish (https://localhost:3000/static/js/bundle.js:154587:315)
at https://localhost:3000/static/js/bundle.js:154682:18
at sentryWrapped (https://localhost:3000/static/js/bundle.js:148904:17)
even with debug: true
set on the sentry client no debug logs are appearing to describe why this is happening. the error from the error boundary never makes it to sentry. but directly calling captureException (from the sentryClient / hub) does work.
The error boundary uses the global hub/client hence the issue: https://github.com/getsentry/sentry-javascript/blob/9ea2bca66a0ca45a83ea5e2369067745cc407e5d/packages/react/src/errorboundary.tsx#L138
We should maybe allow for you to pass a reference to hub in the error boundary.
to be clear i am not using the sentry error boundary. i am using this lib
its usage looks like this
<ErrorBoundary
onReset={reset}
onError={handleErrorBoundaryError}
FallbackComponent={ErrorFallback}
>
the ErrorFallback is just a component to render. the handleErrorBoundaryError
is the callback that shapes / adds some context then calls Sentry.captureException
(the utility i showed above).
even taking zendesk widget out completely i am running into an issue where it states "the error has already been captured" by the time it reaches the callback with Sentry.captureException
.
i want to be in control of what gets sent to sentry so i can do some additional shaping. this works fine on mobile and we thought porting over the logic to web would be trivial but it has become quite a time sink.
it looks like as soon as it touches the error boundary sentry ships it off. then when my callback is invoked it says the error has already been captured.
i tried adding new Sentry.GlobalHandlers({onerror: false, onunhandledrejection: false }),
to the integrations thinking it may disable global capture but it had no effect
@ci-vamp in development mode React maybe capturing the error globally. Could you try running in production mode?
@ci-vamp can you try it again - it should work now (with Zendesk enabled)
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.50.0
Framework Version
17.0.2
Link to Sentry event
No response
SDK Setup
Steps to Reproduce
index.tsx
(root where react render is called)Expected Result
Sentry.captureException sends an exception event to sentry
Actual Result
nothing is sent. nothing in network tab, nothing in beforeSend hook
the only time anything is sent is if i use
Sentry.captureException
in theindex.tsx
directly below theSentry.init
setup.i have tried with
debug
and usingbeforeSend
but the only one that shows up is the one inindex.tsx
.