Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] ReferenceError not being captured by Sentry #4321

Open
shanmukhdontuTWM opened this issue Nov 27, 2024 · 13 comments
Open

[Android] ReferenceError not being captured by Sentry #4321

shanmukhdontuTWM opened this issue Nov 27, 2024 · 13 comments

Comments

@shanmukhdontuTWM
Copy link

shanmukhdontuTWM commented Nov 27, 2024

What React Native libraries do you use?

React Navigation, Hermes

Are you using sentry.io or on-premise?

sentry.io (SaS)

@sentry/react-native SDK Version

5.33.1

How does your development environment look like?

System:
  OS: macOS 14.7.1
  CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
  Memory: 1.37 GB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 18.20.4
    path: ~/.nvm/versions/node/v18.20.4/bin/node
  Yarn:
    version: 1.22.19
    path: /usr/local/bin/yarn
  npm:
    version: 10.7.0
    path: ~/.nvm/versions/node/v18.20.4/bin/npm
  Watchman:
    version: 2024.01.22.00
    path: /usr/local/bin/watchman
Managers:
  CocoaPods: Not Found
SDKs:
  iOS SDK: Not Found
  Android SDK: Not Found
IDEs:
  Android Studio: 2022.3 AI-223.8836.35.2231.10811636
  Xcode:
    version: /undefined
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 11.0.21
    path: /usr/bin/javac
  Ruby:
    version: 2.6.10
    path: /usr/bin/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.2.0
    wanted: 18.2.0
  react-native:
    installed: 0.72.5
    wanted: 0.72.5
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: false
  newArchEnabled: Not found

Sentry.init()

Sentry.init({
      dsn: String(getConfig().SENTRY_DSN),
      environment: String(getConfig().SENTRY_ENVIRONMENT || 'Development'),
      enableUserInteractionTracing: false,
      enableAppStartTracking: false,
      attachScreenshot: false,
      integrations: [
        reactNativeTracingIntegration({
          routingInstrumentation: routingInstrumentation,
        }),
      ],
      debug: false,
      release: deviceInfoModule.getVersion(),
      dist:
        deviceInfoModule.getBundleId() + '-' + deviceInfoModule.getVersion(),
      enabled: true,
    });

Steps to Reproduce

The app is getting initialized with sentry without any issue, and also the sentry crash test is working.
In a component inside the App, it does not have a function imported and is called, which is throwing a ReferenceError locally but the same issue is not populated in sentry. When i converted the function to async, it did the trick.
The app is within the sentry error boundary and we were expecting the crash to show up, even for synchronous functions but thats not the case.
Can someone help look into this?

Expected Result

The event should be logged on sentry dashboard, sentry should capture one.

Actual Result

Sentry not able to capture ReferenceError crashes inside a React native component

@lucas-zimerman
Copy link
Collaborator

lucas-zimerman commented Nov 29, 2024

Hi and thank you for opening this issue!, Could you share the logs from Sentry when debug is set to true?
Also, could you try checking if the problem persists on version 5.34.0?

Lastly, could you share a snippet on how you are calling this function?
Thank you for your patience.

@getsantry getsantry bot moved this to Waiting for: Community in GitHub Issues with 👀 3 Nov 29, 2024
@lucas-zimerman lucas-zimerman moved this from Needs Discussion to Needs More Information in Mobile & Cross Platform SDK Nov 29, 2024
@shanmukhdontuTWM
Copy link
Author

shanmukhdontuTWM commented Dec 3, 2024

@lucas-zimerman Thanks for the prompt response!

 LOG  Sentry Logger [log]: Setting idle transaction on scope. Span ID: 83c00f9b82d42747
 DEBUG  Sentry Logger [debug]: [NativeFrames] Fetching frames for root span start (83c00f9b82d42747).
 LOG  Sentry Logger [log]: [ReactNativeTracing] Starting navigation transaction "Route Change" on scope
 LOG  Sentry Logger [log]: [Tracing] No active IdleTransaction
 LOG  Sentry Logger [log]: [Tracing] Discarding transaction because its trace was not chosen to be sampled.
 LOG  Sentry Logger [log]: Recording outcome: "sample_rate:transaction"
 LOG  Sentry Logger [log]: Setting idle transaction on scope. Span ID: 804914b1fee555d7
 DEBUG  Sentry Logger [debug]: [NativeFrames] Fetching frames for root span start (804914b1fee555d7).
 LOG  Sentry Logger [log]: [ReactNativeTracing] Starting navigation transaction "Route Change" on scope
 LOG  Sentry Logger [log]: [ReactNavigationInstrumentation] A transaction was detected that turned out to be a noop, discarding.
 LOG  Sentry Logger [log]: [Tracing] No active IdleTransaction
 LOG  Sentry Logger [log]: [Tracing] Discarding transaction because its trace was not chosen to be sampled.
 LOG  Sentry Logger [log]: Recording outcome: "sample_rate:transaction"
 LOG  Sentry Logger [log]: Setting idle transaction on scope. Span ID: ab332ad29bccadc3
 DEBUG  Sentry Logger [debug]: [NativeFrames] Fetching frames for root span start (ab332ad29bccadc3).
 LOG  Sentry Logger [log]: [ReactNativeTracing] Starting navigation transaction "Route Change" on scope
 LOG  Sentry Logger [log]: [Tracing] No active IdleTransaction
 LOG  Sentry Logger [log]: [Tracing] Discarding transaction because its trace was not chosen to be sampled.
 LOG  Sentry Logger [log]: Recording outcome: "sample_rate:transaction"
 LOG  Sentry Logger [log]: Setting idle transaction on scope. Span ID: b4cd4921fa3d7207
 DEBUG  Sentry Logger [debug]: [NativeFrames] Fetching frames for root span start (b4cd4921fa3d7207).
 LOG  Sentry Logger [log]: [ReactNativeTracing] Starting navigation transaction "Route Change" on scope
 LOG  Sentry Logger [log]: [Tracing] No active IdleTransaction
 LOG  Sentry Logger [log]: [Tracing] Discarding transaction because its trace was not chosen to be sampled.
 LOG  Sentry Logger [log]: Recording outcome: "sample_rate:transaction"
 LOG  Sentry Logger [log]: Setting idle transaction on scope. Span ID: a2eca104f165c087
 DEBUG  Sentry Logger [debug]: [NativeFrames] Fetching frames for root span start (a2eca104f165c087).
 LOG  Sentry Logger [log]: [ReactNativeTracing] Starting navigation transaction "Route Change" on scope
 LOG  Sentry Logger [log]: [ReactNavigationInstrumentation] A transaction was detected that turned out to be a noop, discarding.
 LOG  Sentry Logger [log]: [Tracing] No active IdleTransaction
 LOG  Sentry Logger [log]: [Tracing] Discarding transaction because its trace was not chosen to be sampled.
 LOG  Sentry Logger [log]: Recording outcome: "sample_rate:transaction"
 LOG  Sentry Logger [log]: Setting idle transaction on scope. Span ID: af0c5d74b4f9f189
 DEBUG  Sentry Logger [debug]: [NativeFrames] Fetching frames for root span start (af0c5d74b4f9f189).
 LOG  Sentry Logger [log]: [ReactNativeTracing] Starting navigation transaction "Route Change" on scope
 LOG  Sentry Logger [log]: [ReactNavigationInstrumentation] Instrumentation already exists, but register has been called again, doing nothing.
 **ERROR  ReferenceError: Property 'callFunction1' doesn't exist**
 LOG  Sentry Logger [log]: [Tracing] No active IdleTransaction
 LOG  Sentry Logger [log]: [Tracing] Discarding transaction because its trace was not chosen to be sampled.
 LOG  Sentry Logger [log]: Recording outcome: "sample_rate:transaction"

Here is the example code snippet

 const functionA = (
    var1: number,
    var2: number,
    var3: string,
  ) => {
    callFunction1({
      param1: {},
      param2: () => callFunction2(),
    });
  };

  useEffect(() => {
    if (
      !varA &&
      ((varQ === '' && !bool) || (varQ === '1' && bool))
    ) {
      const num = 1
      if (num) {
        functionA(
          var1,
          var2,
          var3,
        );
      }
    }
  }, []);

In the above code snippet, callFunction1 is not imported. functionA is called inside the useEffect, which is resulting in ReferenceError locally.
When we convert the functionA to async function, the error event is logged by Sentry and works fine.

Checking v5.34.0, will post the results shortly.

@getsantry getsantry bot moved this from Waiting for: Community to Waiting for: Product Owner in GitHub Issues with 👀 3 Dec 3, 2024
@shanmukhdontuTWM
Copy link
Author

Package update from v5.33.1 -> v5.34.0 did not log the Sentry event as well.

@krystofwoldrich
Copy link
Member

Thank you for the details and testing it with the latest v5.

@getsantry getsantry bot removed the status in GitHub Issues with 👀 3 Dec 4, 2024
@krystofwoldrich krystofwoldrich moved this from Needs More Information to Needs Investigation in Mobile & Cross Platform SDK Dec 4, 2024
@krystofwoldrich
Copy link
Member

@lucas-zimerman Have you reproduced this error?

@lucas-zimerman
Copy link
Collaborator

Hi @krystofwoldrich, I am still investigating this case to see if it's affecting V6 or only V5

@krystofwoldrich
Copy link
Member

Thank you, please post a comment, when you know more/were able to reproduce.

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 3 Dec 13, 2024
@shanmukhdontuTWM
Copy link
Author

I'm able to reproduce this on v6.4.0,
Async function -> logs error event but not the usual sync.
Thanks!

@lucas-zimerman
Copy link
Collaborator

@krystofwoldrich Using the following snippet:

PerformanceScreen.tsx

...

const PerformanceScreen = (props: Props) => {

+    const handleSyncError = () => {
+     undefinedFunction();
+    };

+  React.useEffect(() => {
+    handleSyncError();
+  }, []);

...

So far this is what I found:

  • When attachViewHierarchy or attachScreenshot are set to true and a crash happens at useEffects during a page transition (Errors -> Performance page on sample app), the SDK will hang on the Native callbacks of the screenshot or view hierarchy integration.

Using an async function surely works, but on the other hand React Native doesn't crash in this case, so it could be related to how React Native is dealing with crashes.

Those issues could be related to what @shanmukhdontuTWM is facing, but just as a sanity check, @shanmukhdontuTWM would you be able to make a minimal repro of your issue just to make sure if the issues that I found are related to the issues that you are facing of if you are actually facing another issue?

@shanmukhdontuTWM
Copy link
Author

@lucas-zimerman Currently we are setting attachScreenshot to false and are not using attachViewHierarchy.

As mentioned above, when we set it to async - react native does not crash and sends the event to sentry.

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 3 Dec 16, 2024
@krystofwoldrich
Copy link
Member

Thank you @shanmukhdontuTWM for the details.

@krystofwoldrich
Copy link
Member

krystofwoldrich commented Dec 17, 2024

@lucas-zimerman

The SDK will hang on the Native callbacks of the screenshot or view hierarchy integration.

Can you please investigate this further and share more information here in the thread?

@lucas-zimerman
Copy link
Collaborator

lucas-zimerman commented Dec 17, 2024

@shanmukhdontuTWM when you face the issue with the sync function, does your JS thread gets blocked?

You can test this by running the following code before making the error

    let test2 = 0
    const parsedStack = parseErrorStack(rawStack);
    function printEverySecond(): void {
      setInterval(() => {
        console.log(test2);
        test2++;
      }, 1);
    }

    printEverySecond();

If you don't see any number higher than 0 it means your JS thread got blocked.

Internal:

There seems to be an edge case where undefined synchronous variables may not log if added on useEffects, when an exception happens there, the JS Engine seems to hang/crash.

const prettyStack = await symbolicateStackTrace(parsedStack);

The code above seems to be triggering it, but I don't believe it is doing it because the code is broken, it is more likely the JS engine is going to die so we run on a limited timestamp for logging the error.

It seems like on the sample app if we disable attachScreenshot and attachViewHierarchy, the error gets sent to the native layer in time, otherwise it isn't.
Still, even with those fields changed, if we change the code slightly to

const withTimeout = <T>(promise: Promise<T>, timeoutMs: number): Promise<T | null> => {
  return Promise.race([
    promise,
    new Promise<null>((resolve) => setTimeout(() => {
      resolve(null)
    }, timeoutMs)),
  ]);
};
...
    const prettyStack = await withTimeout(symbolicateStackTrace(parsedStack), 2000);

The SDK will hang and no event will be sent.

When the JS Hang happens, there seems to be a native error that is also not logged:

Unhandled SoftException
      com.facebook.react.bridge.ReactNoCrashSoftException: raiseSoftException(getOrCreateDestroyTask()): handleHostException(message = "addViewAt: failed to insert view [212] into parent [214] at index 0")
      	at com.facebook.react.runtime.ReactHostImpl.raiseSoftException(ReactHostImpl.java:942)
      	at com.facebook.react.runtime.ReactHostImpl.getOrCreateDestroyTask(ReactHostImpl.java:1575)
      	at com.facebook.react.runtime.ReactHostImpl.lambda$destroy$7(ReactHostImpl.java:541)
      	at com.facebook.react.runtime.ReactHostImpl.$r8$lambda$uso21_D6dCZdcf-JomVD56kdG4c(Unknown Source:0)
      	at com.facebook.react.runtime.ReactHostImpl$$ExternalSyntheticLambda37.call(D8$$SyntheticClass:0)
      	at com.facebook.react.runtime.internal.bolts.Task$2.run(Task.java:240)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
      	at java.lang.Thread.run(Thread.java:1012)
      Caused by: java.lang.IllegalStateException: addViewAt: failed to insert view [212] into parent [214] at index 0
      	at com.facebook.react.fabric.mounting.SurfaceMountingManager.addViewAt(SurfaceMountingManager.java:416)
      	at com.facebook.react.fabric.mounting.mountitems.IntBufferBatchMountItem.execute(IntBufferBatchMountItem.java:119)
      	at com.facebook.react.fabric.mounting.MountItemDispatcher.executeOrEnqueue(MountItemDispatcher.java:387)
      	at com.facebook.react.fabric.mounting.MountItemDispatcher.dispatchMountItems(MountItemDispatcher.java:293)
      	at com.facebook.react.fabric.mounting.MountItemDispatcher.tryDispatchMountItems(MountItemDispatcher.java:126)
      	at com.facebook.react.fabric.FabricUIManager$DispatchUIFrameCallback.doFrameGuarded(FabricUIManager.java:1388)
      	at com.facebook.react.fabric.GuardedFrameCallback.doFrame(GuardedFrameCallback.kt:22)
      	at com.facebook.react.modules.core.ReactChoreographer.frameCallback$lambda$1(ReactChoreographer.kt:60)
      	at com.facebook.react.modules.core.ReactChoreographer.$r8$lambda$nSkFhrr5T7rop_XKwzlLov4NLLw(Unknown Source:0)
      	at com.facebook.react.modules.core.ReactChoreographer$$ExternalSyntheticLambda0.doFrame(D8$$SyntheticClass:0)
      	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1337)
      	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1348)
      	at android.view.Choreographer.doCallbacks(Choreographer.java:952)
      	at android.view.Choreographer.doFrame(Choreographer.java:878)
      	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1322)
      	at android.os.Handler.handleCallback(Handler.java:958)
      	at android.os.Handler.dispatchMessage(Handler.java:99)
      	at android.os.Looper.loopOnce(Looper.java:205)
      	at android.os.Looper.loop(Looper.java:294)
      	at android.app.ActivityThread.main(ActivityThread.java:8177)
      	at java.lang.reflect.Method.invoke(Native Method)
      	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
      	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
      Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
      	at android.view.ViewGroup.addViewInner(ViewGroup.java:5275)
      	at android.view.ViewGroup.addView(ViewGroup.java:5104)
      	at com.facebook.react.views.view.ReactViewGroup.addView(ReactViewGroup.java:608)
      	at android.view.ViewGroup.addView(ViewGroup.java:5044)
      	at com.facebook.react.views.view.ReactClippingViewManager.addView(ReactClippingViewManager.java:41)
      	at com.facebook.react.views.view.ReactClippingViewManager.addView(ReactClippingViewManager.java:21)
      	at com.facebook.react.fabric.mounting.SurfaceMountingManager.addViewAt(SurfaceMountingManager.java:413)
      	at com.facebook.react.fabric.mounting.mountitems.IntBufferBatchMountItem.execute(IntBufferBatchMountItem.java:119) 
      	at com.facebook.react.fabric.mounting.MountItemDispatcher.executeOrEnqueue(MountItemDispatcher.java:387) 
      	at com.facebook.react.fabric.mounting.MountItemDispatcher.dispatchMountItems(MountItemDispatcher.java:293) 
      	at com.facebook.react.fabric.mounting.MountItemDispatcher.tryDispatchMountItems(MountItemDispatcher.java:126) 
      	at com.facebook.react.fabric.FabricUIManager$DispatchUIFrameCallback.doFrameGuarded(FabricUIManager.java:1388) 
      	at com.facebook.react.fabric.GuardedFrameCallback.doFrame(GuardedFrameCallback.kt:22) 
      	at com.facebook.react.modules.core.ReactChoreographer.frameCallback$lambda$1(ReactChoreographer.kt:60) 
      	at com.facebook.react.modules.core.ReactChoreographer.$r8$lambda$nSkFhrr5T7rop_XKwzlLov4NLLw(Unknown Source:0) 
      	at com.facebook.react.modules.core.ReactChoreographer$$ExternalSyntheticLambda0.doFrame(D8$$SyntheticClass:0) 
      	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1337) 
      	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1348) 
      	at android.view.Choreographer.doCallbacks(Choreographer.java:952) 
      	at android.view.Choreographer.doFrame(Choreographer.java:878) 
      	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1322) 
      	at android.os.Handler.handleCallback(Handler.java:958) 
      	at android.os.Handler.dispatchMessage(Handler.java:99) 
      	at android.os.Looper.loopOnce(Looper.java:205) 
      	at android.os.Looper.loop(Looper.java:294) 
      	at android.app.ActivityThread.main(ActivityThread.java:8177) 
      	at java.lang.reflect.Method.invoke(Native Method) 
      	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) 
      	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Status: Needs Investigation
Development

No branches or pull requests

3 participants