bugsnag / bugsnag-react-native

Error monitoring and reporting tool for native exceptions and JS errors in React Native apps
https://docs.bugsnag.com/platforms/react-native
MIT License
370 stars 121 forks source link

java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.String #430

Closed WouterFlorijn closed 4 years ago

WouterFlorijn commented 4 years ago

Description

I'm calling client.setUser(userId) where userId is a number.

See code snippet below for how I'm initializing the client.

Issue

Expected result:

Either I get a JS exception showing me a useful error message and stack trace, or the number (double in Java) gets cast to string.

Actual result:

The following exception is thrown (only in production mode - in development everything works):

java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.String                                       
       at com.facebook.react.bridge.ReadableNativeArray.getString(ReadableNativeArray.java:135)                         
       at com.facebook.react.bridge.JavaMethodWrapper$5.extractArgument(JavaMethodWrapper.java:73)                      
       at com.facebook.react.bridge.JavaMethodWrapper$5.extractArgument(JavaMethodWrapper.java:69)                      
       at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:359)                                
       at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:158)                                
       at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)                                             
       at android.os.Handler.handleCallback(Handler.java:873)                                                           
       at android.os.Handler.dispatchMessage(Handler.java:99)                                                           
       at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29)  
       at android.os.Looper.loop(Looper.java:193)                                                                       
       at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:232)                 
       at java.lang.Thread.run(Thread.java:764)

This provides zero context and makes it very difficult to debug. Especially as this error isn't thrown in development. I basically had to try out commits in my repo randomly to find out what caused the error.

Environment

Library versions:

+-- bugsnag-react-native@2.22.6
`-- react-native@0.59.8

Example code snippet

import { Client, Configuration } from 'bugsnag-react-native'

const options = new Configuration(BUGSNAG_API_KEY)

options.registerBeforeSendCallback(() => !__DEV__) // I tried turning this off in development mode to reproduce the error, but it wasn't reproducable.

const client = new Client(options)
Error messages: ``` java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.String at com.facebook.react.bridge.ReadableNativeArray.getString(ReadableNativeArray.java:135) at com.facebook.react.bridge.JavaMethodWrapper$5.extractArgument(JavaMethodWrapper.java:73) at com.facebook.react.bridge.JavaMethodWrapper$5.extractArgument(JavaMethodWrapper.java:69) at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:359) at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:158) at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29) at android.os.Looper.loop(Looper.java:193) at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:232) at java.lang.Thread.run(Thread.java:764) ```
mattdyoung commented 4 years ago

Hi @WouterFlorijn

I'm unable to reproduce this behaviour on react-native 0.59.8 and the latest bugsnag-react-native.

Configuring an example app following the docs with the following configuration works on both debug and release builds on Android, and the numeric user ID is correctly reported:

import { Client } from 'bugsnag-react-native';
const bugsnag = new Client('YOUR_API_KEY_HERE');

bugsnag.setUser(123.45);
bugsnag.notify(new Error('MyError'));

Can you share a reproduction case which demonstrates the error your report on the latest bugsnag-react-native?

WouterFlorijn commented 4 years ago

@mattdyoung could it be device-specific? According to our monitoring, it has only occured on Oneplus devices (at least ONEPLUS A6003 and ONEPLUS A5000), though for multiple different users.

mattdyoung commented 4 years ago

It is possible it's device-specific, but it would seem odd - the error isn't particularly low-level.

Is my attempted reproduction case how you're using setUser? i.e. you're setting it in Javascript not in underlying Android Java code?

How confident are you that it's that field causing the issue?

To look into this further it would be useful if you could share the code you're using to set this and a link to the resulting error in your Bugsnag dashboard (please email to support@bugsnag.com if you'd rather not share the details here).

WouterFlorijn commented 4 years ago

@mattdyoung I'm using it like this:

bugsnag.setUser(1234)

So with integers, though I'm not sure if that's any different from floats/decimals in this case, since they're all numbers.

I'm fairly certain the error is caused by the setUser call. Since I've changed it to bugsnag.setUser(userId.toString()), the error hasn't occured anymore. Though I agree it's strange that it only occured on one device brand.

I don't really see anything else that may be relevant in the Bugsnag error, except that the following threads are present:

Thread 69826·Bugsnag Thread #1

Object.java:-2java.lang.Object.wait 
Thread.java:2137java.lang.Thread.parkFor$ 
Unsafe.java:358sun.misc.Unsafe.park 
LockSupport.java:190java.util.concurrent.locks.LockSupport.park 
AbstractQueuedSynchronizer.java:2059java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await 
LinkedBlockingQueue.java:442java.util.concurrent.LinkedBlockingQueue.take 
ThreadPoolExecutor.java:1092java.util.concurrent.ThreadPoolExecutor.getTask 
ThreadPoolExecutor.java:1152java.util.concurrent.ThreadPoolExecutor.runWorker 
ThreadPoolExecutor.java:641java.util.concurrent.ThreadPoolExecutor$Worker.run 
Thread.java:764java.lang.Thread.run 

Thread 69827·Bugsnag Thread #2

Object.java:-2java.lang.Object.wait 
Thread.java:2137java.lang.Thread.parkFor$ 
Unsafe.java:358sun.misc.Unsafe.park 
LockSupport.java:190java.util.concurrent.locks.LockSupport.park 
AbstractQueuedSynchronizer.java:2059java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await 
LinkedBlockingQueue.java:442java.util.concurrent.LinkedBlockingQueue.take 
ThreadPoolExecutor.java:1092java.util.concurrent.ThreadPoolExecutor.getTask 
ThreadPoolExecutor.java:1152java.util.concurrent.ThreadPoolExecutor.runWorker 
ThreadPoolExecutor.java:641java.util.concurrent.ThreadPoolExecutor$Worker.run 
Thread.java:764java.lang.Thread.run 

Thread 69828·Bugsnag Thread #3

Object.java:-2java.lang.Object.wait 
Thread.java:2137java.lang.Thread.parkFor$ 
Unsafe.java:358sun.misc.Unsafe.park 
LockSupport.java:190java.util.concurrent.locks.LockSupport.park 
AbstractQueuedSynchronizer.java:2059java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await 
LinkedBlockingQueue.java:442java.util.concurrent.LinkedBlockingQueue.take 
ThreadPoolExecutor.java:1092java.util.concurrent.ThreadPoolExecutor.getTask 
ThreadPoolExecutor.java:1152java.util.concurrent.ThreadPoolExecutor.runWorker 
ThreadPoolExecutor.java:641java.util.concurrent.ThreadPoolExecutor$Worker.run 
Thread.java:764java.lang.Thread.run 

Thread 69829·Bugsnag Thread #4

Object.java:-2java.lang.Object.wait 
Thread.java:2137java.lang.Thread.parkFor$ 
Unsafe.java:358sun.misc.Unsafe.park 
LockSupport.java:190java.util.concurrent.locks.LockSupport.park 
AbstractQueuedSynchronizer.java:2059java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await 
LinkedBlockingQueue.java:442java.util.concurrent.LinkedBlockingQueue.take 
ThreadPoolExecutor.java:1092java.util.concurrent.ThreadPoolExecutor.getTask 
ThreadPoolExecutor.java:1152java.util.concurrent.ThreadPoolExecutor.runWorker 
ThreadPoolExecutor.java:641java.util.concurrent.ThreadPoolExecutor$Worker.run 
Thread.java:764java.lang.Thread.run
abigailbramble commented 4 years ago

Hi @WouterFlorijn - We are still unable to reproduce this issue.

Generally, we expect the user id to be a string. See our documentation: https://docs.bugsnag.com/platforms/react-native/react-native/configuration-options/#setuser https://docs.bugsnag.com/platforms/android/configuration-options/#setuser https://docs.bugsnag.com/platforms/android/customizing-error-reports/#setuser

As this has only occurred for one type of device and you have worked around this issue, I will close for now. If you are able to provide a standalone reproduction example, we may be able to investigate this further.