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

Debugging React Native #69

Open
cpojer opened this issue Dec 11, 2018 · 56 comments
Open

Debugging React Native #69

cpojer opened this issue Dec 11, 2018 · 56 comments
Labels
🗣 Discussion This label identifies an ongoing discussion on a subject

Comments

@cpojer
Copy link
Member

cpojer commented Dec 11, 2018

This issue is part of What do you dislike about React Native?.

The second most voted answer was that debugging React Native is painful, see #64 (comment).

The problem statement is very broad ("Debugging is hard") and we would like to gather more context about the actual issues that people are experiencing. Please use this issue to list every piece of content you can related to debugging React Native: your own stories, links to issues, blog posts, complaints or any other rants you can find. Thank you!

@cpojer cpojer changed the title Debugging Exceptions with React Native Debugging with React Native Dec 11, 2018
@cpojer cpojer changed the title Debugging with React Native Debugging React Native Dec 11, 2018
@matt-oakes
Copy link
Member

Systrace - Issue #15003

Systrace is one useful tool which has been broken in the open source release for 1.5 years now with no available fix or workaround.

Initially it was due to the change away from RCTBatchedBridge (workaround here), however, now that it has been removed completely there is no workaround. Another workaround which was given was to use the Chrome debugger, however, this is not the same sort of tool.

The actual issue is that Facebook's fork of React Native has a private library which allows Systrace to work. @gaearon originally posted that it would be looked at in December 2017 or January 2018. In August 2018 @axemclion confirmed that this was not an issue for the internal Facebook version. The proposed solution was for the community to submit a PR on top of an unspecified "very old" PR.

It's a tool that you don't need to use too often, but that fact that it is included in the development menu but has been completely broken for 1.5 years is not a good situation to be in.

As @jamesreggio stated, the community ideally should have stepped up to fix this, however, it would likely take a non-trivial amount of time and could conflict with Facebook's internal tool which would lead to any PR opened to fix the issue being a real slog to get merged (even more than usual). For me, the obvious solution is for Facebook to submit their implemrntation to the open source project, however, it's not clear if that is allowed to happen.

@slorber
Copy link

slorber commented Dec 11, 2018

Hi,

For me the issue I get the most is "unactionnable stacktraces"

image

Usually when having a stacktrace, we can click a stack item and be lead to the original place of the exception. But very often, the stacktrace of uncaught exceptions, or exceptions received in error boundaries are totally unhelpful. It looks to me at some point the stacktrace is lost. If I put a try/catch in render, I'll get the correct stacktrace, but if the exception propagates to upper levels it is lost.

I'd like that an exception thrown in render, and logged in componentDidCatch, to have the same stacktrace as the if I put a try/catch in render myself. ie: clicking on the first stacktrace item would lead to the root cause.

@noahtallen
Copy link

noahtallen commented Dec 11, 2018

I sometimes get crashes when opening the app that don't result in red screens. These can be caused by configuration of native code, and I end up having to open logcat for Android or Xcode to read what the native-level logs are telling me. Since that info already exists, it'd be nice to have an easier way to access it than by actually opening logcat or Xcode.

@noahtallen
Copy link

Separately, regarding stack traces, it seems that I don't reliably get line numbers, or at least the line numbers are unhelpful. Sometimes I just get a reference to the bundle file. As in @slorber 's screen shot, ExceptionsManager.js or MessageQueue.js or debuggerWorker.js come up in stack traces all the time, but are never helpful for figuring out what the error was. To clarify, every line of that stack trace refers to the code that is handling the thrown error internally within react-native, not to where the error originated in our code.

Along with that, cannot read property x of undefined errors are pretty common, and it would be very nice to know which variable, or which object property was actually undefined.

@thomaschriskelly
Copy link

Debugging network requests feels kludgy. There are lots of different solutions, but nothing standardized.

@plrdev
Copy link

plrdev commented Dec 11, 2018

Hot reloading is awesome, but is not working as good as it could (actually it is even crashing for me on iOS if I am not debugging).

Dan Abramov had a real good blog post about what would make hot reloading great (also makes a point that rn implementation is not complete): https://overreacted.io/my-wishlist-for-hot-reloading/

@cdunkel
Copy link

cdunkel commented Dec 12, 2018

When debugging the app in iOS, the number of times that I get a red error screen telling me that the package server is not ready for debugging, when it absolutely is, is very frustrating, especially if it happens during the testing of a sequence of events and reloading the view takes me back to the beginning of the sequence. Often my only option is to restart the application and hope that it works better next time.

@noahtallen
Copy link

To second that, often it will remain on "not ready for debugging" directly after telling it to debug JS remotely - I'm guessing because the server is in the process of launching. You have to refresh again for it to actually connect.

@bartolkaruza
Copy link

bartolkaruza commented Dec 29, 2018

This issue seems to persist in the wild; facebook/react-native#12830 It is related to AsyncStorage blocking (not resolving) during debug sessions on iOS/Android device/emulator/simulator and variants. I personally have not experienced it recently.

@noahtallen
Copy link

An ongoing bug which I'm getting really highlights how inadequate React Native's tooling is when it comes to figuring out where a native crash originates in your JS code. Let me outline the issue and point out the debugging pain points.

The Android crash report shows the following:

Fatal Exception: com.facebook.react.bridge.JSApplicationIllegalArgumentException: Error while updating property 'transform' of a view managed by: RCTView
       at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:95)
       at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:132)
       at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:51)
       at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:32)
       at com.facebook.react.uimanager.NativeViewHierarchyManager.updateProperties(NativeViewHierarchyManager.java:138)
       at com.facebook.react.uimanager.UIViewOperationQueue$UpdatePropertiesOperation.execute(UIViewOperationQueue.java:95)
       at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:894)
       at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:1001)
       at com.facebook.react.uimanager.UIViewOperationQueue.access$2400(UIViewOperationQueue.java:46)
       at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1061)
       at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
       at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:134)
       at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:105)
       at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909)
       at android.view.Choreographer.doCallbacks(Choreographer.java:723)
       at android.view.Choreographer.doFrame(Choreographer.java:655)
       at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
       at android.os.Handler.handleCallback(Handler.java:789)
       at android.os.Handler.dispatchMessage(Handler.java:98)
       at android.os.Looper.loop(Looper.java:164)
       at android.app.ActivityThread.main(ActivityThread.java:6694)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)
Caused by java.lang.reflect.InvocationTargetException java.lang.reflect.Method.invoke
Caused by java.lang.reflect.InvocationTargetException
       at java.lang.reflect.Method.invoke(Method.java)
       at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:83)
       at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:132)
       at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:51)
       at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:32)
       at com.facebook.react.uimanager.NativeViewHierarchyManager.updateProperties(NativeViewHierarchyManager.java:138)
       at com.facebook.react.uimanager.UIViewOperationQueue$UpdatePropertiesOperation.execute(UIViewOperationQueue.java:95)
       at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:894)
       at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:1001)
       at com.facebook.react.uimanager.UIViewOperationQueue.access$2400(UIViewOperationQueue.java:46)
       at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1061)
       at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
       at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:134)
       at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:105)
       at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909)
       at android.view.Choreographer.doCallbacks(Choreographer.java:723)
       at android.view.Choreographer.doFrame(Choreographer.java:655)
       at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
       at android.os.Handler.handleCallback(Handler.java:789)
       at android.os.Handler.dispatchMessage(Handler.java:98)
       at android.os.Looper.loop(Looper.java:164)
       at android.app.ActivityThread.main(ActivityThread.java:6694)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)
Caused by com.facebook.react.bridge.NoSuchKeyException: translateX
Caused by com.facebook.react.bridge.NoSuchKeyException: translateX
       at com.facebook.react.bridge.ReadableNativeMap.getValue(ReadableNativeMap.java:122)
       at com.facebook.react.bridge.ReadableNativeMap.getValue(ReadableNativeMap.java:126)
       at com.facebook.react.bridge.ReadableNativeMap.getDouble(ReadableNativeMap.java:168)
       at com.facebook.react.uimanager.TransformHelper.processTransform(TransformHelper.java:82)
       at com.facebook.react.uimanager.BaseViewManager.setTransformProperty(BaseViewManager.java:213)
       at com.facebook.react.uimanager.BaseViewManager.setTransform(BaseViewManager.java:69)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:83)
       at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:132)
       at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:51)
       at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:32)
       at com.facebook.react.uimanager.NativeViewHierarchyManager.updateProperties(NativeViewHierarchyManager.java:138)
       at com.facebook.react.uimanager.UIViewOperationQueue$UpdatePropertiesOperation.execute(UIViewOperationQueue.java:95)
       at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:894)
       at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:1001)
       at com.facebook.react.uimanager.UIViewOperationQueue.access$2400(UIViewOperationQueue.java:46)
       at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1061)
       at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
       at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:134)
       at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:105)
       at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909)
       at android.view.Choreographer.doCallbacks(Choreographer.java:723)
       at android.view.Choreographer.doFrame(Choreographer.java:655)
       at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
       at android.os.Handler.handleCallback(Handler.java:789)
       at android.os.Handler.dispatchMessage(Handler.java:98)
       at android.os.Looper.loop(Looper.java:164)
       at android.app.ActivityThread.main(ActivityThread.java:6694)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)

For iOS, in release mode, it doesn't actually crash the app. But for some reason, the interface freezes up and doesn't respond well, or unexpected things happen when you tap buttons. However, I can sometimes replicate the crash locally, and the Xcode log says:

-[NSNull floatValue]: unrecognized selector sent to instance 0x112e63f28

The redscreen crash that shows up in the simulator indicates that translateX has been given the value null, and that isn't allowed. This is basically the same as what shows up in the Android emulator too. Sometimes these crashes also indicate the View ID (e.g. "View with ID #777" or something like that).

So far in the debugging experience, I know that a crash happens, and that it's caused because at some point translateX is set to null. So I know that this is a UI rendering issue because this is a style property. However, there is no indication of where this crash happens or what user behavior causes it because it doesn't happen every time you run the app.

After further investigation, I found that it typically happens after a particular action happens. So now I can reproduce it in a simulator fairly regularly (though still not 100% reliably). At this point, I need to figure out where translateX is getting improperly set. So I do a global search for translateX. I find out the following:

  1. I never use translateX in my own code. So it is caused by a 3rd party library.
  2. The word translateX occurs 221 times in node_modules. So figuring out which one causes it will be difficult.

My next thought with debugging was to set a breakpoint in Xcode whenever any exception happens, so I can see much more detailed information about the crash. This worked really well, I was able to examine the call stack and local variables for the entire crash.

However, the call stack was entirely internal react-native code. Since the transform values are obviously sent over the JS bridge, after it gets into the native code, everything is handled by fairly generic code which runs on every translateX set. A lot of this code also handles any style property.

Natively debugging the crash only showed me the local variables for native code - but it was impossible to figure out which of this code ties back to my JS code. I need to know which component it originates from in order to fix it or to file a bug report. The most I could find out after some digging through the stack trace was the backgroundColor of the view, and the "pseudo ID" of the view. I used react-native-debugger to look through the React views of my app, but that doesn't show any sort of ID for the views, so I still can't figure out which view causes the issue.

While setting a breakpoint in the native code, I pulled out the data structure which contains the null value. It looks like this:
screen shot 2018-12-24 at 12 00 07 am

I'm not sure why null was never validated before it got to the point in native code where it tried to apply the transform logic to the values. Seems like it should have been.

Doing a bit more thought, my next hunch is based on the fact that the action sets particular redux state that re-renders a component. And that component would not be visible when the redux state updates. Thinking about the components that would update, I narrowed my search for translateX to a react-native-progress, and found a bit of code in react-native-progress/Bar.js which calls translateX, and also looks surprisingly similar to the data structure which causes the issue:

    const progressStyle = {
      backgroundColor: color,
      height,
      transform: [
        {
          translateX: this.state.animationValue.interpolate({
            inputRange: [0, 1],
            outputRange: [innerWidth * -INDETERMINATE_WIDTH_FACTOR, innerWidth],
          }),
        },
        {
          translateX: this.state.progress.interpolate({
            inputRange: [0, 1],
            outputRange: [innerWidth / -2, 0],
          }),
        },
        {
          // Interpolation a temp workaround for https://github.com/facebook/react-native/issues/6278
          scaleX: this.state.progress.interpolate({
            inputRange: [0, 1],
            outputRange: [0.0001, 1],
          }),
        },
      ],
    };

This array is set up with the same order and same properties that the object which causes the issue has been. That's really encouraging. But now I need to figure out why any of those values would ever be set to null.

So I set console.log() in the progress library for each of the array elements, like:translateX.__getValue(), expecting to see something fishy when triggering the crash. But the values are 100% normal up to the crash, and nothing looks weird at the time of the crash.

So at this point I've been investigating this crash for more than 20 hours, and the existing similar issues and Stack Overflow posts are rare and unhelpful.

I've outlined this debugging experience so that you have some more material examples of how difficult it can be to debug React Native issues. Here are my big takeaways:

  1. Native crashes almost never include the information necessary to tie the crash back to the JS code you wrote that causes the issue.
  2. While debugging, it's not possible to look at a native function which has been called from JS and see which React view or component it is operating on.
  3. The native call stack is basically a chain of functions in which 80% of them have to do with internal rendering stuff which is rarely at fault for these sorts of issues. Obviously, that's just how the code is written so there's not much to change, but it means that the given information is really inadequate.

Basically, I think my conclusion is that there has to be some easy way to debug through the JS bridge such that internal React Native functions that actually do the bridge work are hidden. For example, I would rarely want to have any information about the internal functions which actually implement the bridge on both the JS and Native sides. But as is, the majority of debug information is just printing out the internal bridge implementation and view updating code. What we need to know is what JS file this error originated from, and how it propagated through our own code, or through a 3rd party library's code, in order to end up in a bad state.

It definitely seems like a really tough problem to solve, so I hope this post has been helpful, though it is quite long. Happy Holidays! :)

P.S. If you have any suggestions for actually fixing this dang crash, please let me know!

@elicwhite
Copy link

@noahtallen thank you so much for that level of detail. It is amazingly helpful and really shows the scope of the problem, especially when dealing with 3rd party code. This is definitely something we will need to talk about as a group.

@bartolkaruza
Copy link

Systrace is one useful tool which has been broken in the open source release for 1.5 years now with no available fix or workaround.

@matt-oakes Have you tried the Javascript Profiler in the standalone React Native Debugger? You can select the debug worker thread to make flame charts of JS calls. I use it a lot to find out why the JS thread is not keeping up. I find that using the javascript profiler, combined with Android systrace and various iOS Instruments, is a decent workaround to get insight in what is slowing down any app.

I agree Systrace should be fixed of course.

@aleclarson
Copy link

aleclarson commented Feb 3, 2019

When you make a change to a file in your bundle and restart your app (either from Xcode or via the "Reload JS" button), breakpoints in Chrome devtools are not respected. This might be because it takes time for Chrome devtools to process the source map. It would be great if the RN team looked into it!

@cpojer
Copy link
Member Author

cpojer commented Apr 9, 2019

Hey everyone! Thanks so much for participating in this discussion so far. I think we have a good understanding of things that are broken. I'm interested in fixing a ton of the smaller annoyances, like unhelpful error messages. A lot of you have been sharing error messages but no clear repros. Would you mind sending me your best code examples that I can just drop into my App.js of a new RN app that will either crash, generate an unhelpful error or otherwise cause trouble that you think needs attention? Thank you!

@jamonholmgren
Copy link
Collaborator

jamonholmgren commented Apr 9, 2019

Here's one: Unhandled Promise Rejections have unhelpful stack traces, @cpojer. We deal with this a lot.

import React, {Component} from 'react';
import {Text, View} from 'react-native';

export default class App extends Component {
  componentDidMount() {
    async function crash() {
      throw new Error('crashed')
    }
    crash()
  }

  render() {
    return <View><Text>Jamon</Text></View>;
  }
}

image

@namvoeh
Copy link

namvoeh commented Apr 10, 2019

My app got this issue on Sentry Invariant Violation: Text strings must be rendered within a <Text> component., I spent a few days to find the cause but I couldn't, then my team come with a solution that set display name for every component, any suggestions to discover the cause?

@h4run

This comment has been minimized.

@namvoeh

This comment has been minimized.

@vreality64
Copy link

@namvoeh
How can you render your component? Rendering based on condition like { condition && <Component /> } usage may occur that error in runtime. Here are expo code.

Cause is empty string ('') and zero (0)

// Invariant Violation Error 
const Foo = () => (
  <View>
    { '' && <Bar /> }  // if value is empty string
    { 0 && <Bar /> } // if value is zero
  </View>
)

const Foo = () => (
  <View>
    { value ? <Bar /> : null }  // 1. use ternary operator
    { !!value && <Bar /> }  // 2. use !! expression to make it boolean value
  </View>
)

I hope this will help you 😃

@namvoeh

This comment has been minimized.

@pavermakov

This comment has been minimized.

@cpojer
Copy link
Member Author

cpojer commented Apr 10, 2019

Thanks for participating in the discussion. Please do not discuss how to solve specific problems here as it's not a support forum. I'm looking for concrete code examples that lead to bad errors or crashes. Screenshots of issues without repro steps are unfortunately not really actionable.

@mschipperheyn

This comment has been minimized.

@top-master
Copy link

When we write something like:

let console = require("console");

result:

Unknown
run
    NativeRunnable.java
handleCallback
    Handler.java:873
dispatchMessage
    Handler.java:99
dispatchMessage
    MessageQueueThreadHandler.java:29
loop
    Looper.java:193
run
    MessageQueueThreadImpl.java:232
run
    Thread.java:764

@osdnk
Copy link
Member

osdnk commented Apr 27, 2019

@adamczyk777 You're making sth similar in reanimated. Maybe you want to push it here as well?

@pk936
Copy link

pk936 commented Apr 30, 2019

Any solution to this problem ?

@jkadamczyk
Copy link

As @osdnk mentioned before I was trying to resolve some issues with poor error messages in ReadableMap and other types that are used when passing stuff through the bridge. Here's a link to PR I opened a while ago Link.

So what's the issue right here?

Let's focus on Android first, because that was the case that started the discussion about it in reanimated. When we pass objects that describe animated nodes, the JS object after being passed through bridge gets translated to ReadableMap. The problem is that when accessing data in Java, there might be a case when the value is some NaN or undefined and is not passed correctly but we have code that expects string cause we are calling getString`. If the situation like described happens there is an error that looks just like this Reanimated Issue. It doesn't say much to anyone. What I've done to overcome that and make the experience more friendly to Reanimated users was wrapping the retrieving of the value and giving personalized error messages. I knew which parts of native code reference to which parts in JS so to make stuff easier I pointed to those parts in those error messages. We partially got rid of the issue because we made things more strict on JS side by using invariant and checking if the user passes the actual node or some weird exotic value instead and most of the time wrong value won't even get past this wall.

What would be cool to have in the future?

Default error messages could be better by default, not only huge "what". Also if getString was overloaded and there was a possibility to pass an error message if a problem occurs when reading a value that would also be great.

That's for Android, the problem on iOS also exists, because values get cast to different values, in ReadableMap there is no warranty of types or sth like this. In the end, I also wrote error messages through objC macro when the value is wrong I print the same error messages as in Java.

Hope my comment makes sense, if not reply I can clarify 😃

@cihadturhan
Copy link

Sometimes it becomes pain to debug the app because you are not sure where to look at. If you are experienced developer, you can spot the problem but this is just a frustration to a newcomer

Problem 1

The most difficult bug to debug is when you left a text accidentally outside of a text component. Eg.

<View>
 <Text>Hello World</Text>>
<View>                   ^

Text strings must be rendered within a component

And its error message doesn't help much. You have to manually search to component to find if there is any extra character.

My suggestion is

  • Instead of crashing whole app, create a Text component include text nodes
<View>
 <Text>Hello World</Text><Text>></Text>
<View>                   
  • Change error to warning

Problem 2

Another similar error message is when you provide null uri to an Image element:

class MyComp extends Component {
 state = {
   uri: null
 }
  render(){
    <View><Image source={{uri: this.state.uri}} /> </View>
  }
}

JSON value '' of type NSNull cannot be converted to NSString

My suggestion is

  • Convert null to empty string and show empty image
  • Change error to warning

@x5engine
Copy link

RN is like black magic, sometimes it works and other it doesn't, it's like that, deal with it :D

@evelant
Copy link

evelant commented Feb 20, 2020

None of the debugging tools listed in the documentation work as stated in the docs anymore. Some kinda work, some are totally broken, but there are really no working options left for debugging UI performance, at least on Android.

Systrace is broken, it is missing the information the docs state it should show.

Chrome debugger no longer records user timings or any information in the performance tab. It only records the debugger webpage now. This means chrome debugger is limited to viewing console logs and taking basic CPU profiles. The most useful tools no longer work.

react-devtools are broken, they lose connection to the app constantly making profiling impossible. They also commonly reduce performance to the point the app is unusable making the tools useless for debugging especially perf related things.

Needless to say this is extremely frustrating. Users complain about poor performance on Android but we have no tools to diagnose and fix the issues!

@xutm
Copy link

xutm commented Feb 27, 2020

How to debug js thread block in production?
I find it difficult to have a corresponding method or tool to help solve the problem, only through dichotomy to solve. But that's inefficient. I don't know if I know too little, or if this is a difficult problem to solve.

@hugoh59
Copy link

hugoh59 commented May 18, 2020

I'm also looking for solution, I've been following this issue for a few months but still no working solutions in the latest updates.

@varemenos
Copy link

varemenos commented Jul 5, 2020

I'm surprised it wasn't mentioned yet (maybe it's off topic?) but I'd really like a way to trace/detect component updates. I recently authored a not so well written component that would re-render indefinitely but wouldn't crash the app so it was hard to notice.

I know this was removed and readded for DOM only. It'd be awesome if we had RN support too.

@evelant
Copy link

evelant commented Jul 10, 2020

Debugging in general is an awful, even unusable at times, experience on the Android Studio emulator. It slows the app down (especially animations) to the point where the debugger is sometimes unusable. I've tried all the tricks removing console logs, different android versions in emulator, checking time matches, checking haxm acceleration, different emulator configurations, using hermes. None of it helps. I'm on a very fast modern desktop machine so it's not my machine perf. There are a few symptoms:

  • Performance is decent in dev mode with debugger off.
  • Performance is very good in a release build.
  • General performance on the android emulator seems to be about 10x or more slower with the debugger connected (vscode or chrome)
  • Animations seem to be buggy only in debug/dev mode. Sometimes two unrelated animations appear to wait for the other to finish when they shouldn't. Stagger animations wait for the first element to finish animating before properly animating all the subsequent ones.
  • There are random crashes, especially with hermes enabled but also with JSC
  • React-devtools tanks performance so hard that it can't be used. It disconnects randomly a lot anyway.

Perhaps the worst part about this is that there's no way to diagnose the issues. Per my previous post in this thread most of the Android perf tools are broken. Sometimes the chrome timeline works but it shows no issues with my app code, whatever is killing perf is inside RN out of reach of the JS thread.

This all leads to a supremely frustrating experience. There are only two ways to debug my app -- via console.log spam or via buying a mac where iOS simulator perf is flawless and stable.

@gwmccull
Copy link

@AndrewMorsillo I don't think buying a mac will fix anything. I'm on a 2018 MBP and Android emulator performance is the same as what you describe

I was recently building an accordion component using react-native-collapsible. On the iOS simulator it was fine with or without debugging. On the Android emulator without debugging it was fine. On the Android emulator with debugging it would take 1-2 seconds from tap to the time the animation started. And besides starting late, the animation seemed to run slowly

I tried using why-did-you-render to detect any unnecessary React rerendering but none was found. Many of the components involved used React.memo to improve perf

@evelant
Copy link

evelant commented Jul 10, 2020

@gwmccull When I said "buy a mac" I meant to use the iOS simulator. The iOS simulator has a perfectly smooth experience debugging react-native. The Android debugging situation is terrible on any platform. It's especially problematic for my use case because we have animations running nearly constantly in the app. Turn on Android debugging and a tap can take 2-6 seconds to register which isn't really usable for debugging.

@liamjones
Copy link

liamjones commented Jul 10, 2020

For Android debugging I've generally given up on the emulator due to the slowness and use a real device via Vysor instead: https://vysor.io/ It's been working reasonably well so far...

Using Vysor rather than just the device directly means I have it on my desktop to tab to, like the emulator and I can use R R to refresh, etc rather than having to shake the physical device

@terrysahaidak
Copy link

For Android, I think the cause of this are some options of the used AVD. There are quite few responsible for performance when you creating an AVD.

on my MBP 15 2018 AVD works like a lot better than the iOS simulators (even iPhone SE not that smooth).

But I cannot point where those changes should be made.

But the downside of it is usage of 100% of the thread all the time.

@jasonliu0704
Copy link

Hey folks, so this has been for almost 2 years. Any improvement or action item resolves around this? I am still.having a bad experience debugging react.

@cederom
Copy link

cederom commented Aug 29, 2021

Well I can debug Unix software and drivers, I can debug remote microcontroller running firmware over JTAG/SWD, but I could not get into debugging my React Native application running on the real phone over USB. I just get some website but where is the debugger so I can trace my application? Where are instructions and examples? The documentation is laconic and not really hlepful for noobs in JS/RN ;-)

@gwmccull
Copy link

@cederom that website is the debugging tool. You can open the Chrome console and see any console statements logged out there. The metro bundler (in the terminal) will also show console statements.

The Chrome console also allows you to switch to the source and do real-time debugging with breakpoints, step through lines of code, etc. However, the debugger can be a little difficult to use because it's easy to fall out of a component function and end up in a function from React or another library

I generally just use console.log statements for 99% of my debugging

@cederom
Copy link

cederom commented Aug 31, 2021

Hello @gwmccull :-) Thanks for the hints :-)

What you mention seems Logging not Debugging. I have done that already by hand inside my code to know that is going on, what is the progress, what is the data, etc. But this is just a log that I need to create myself by hand. I have it directly on my expo-cli so what is the purpose of using yet another site just for logging? Btw. can you recommeng a log library that can give filename/function/linenumber shortcut by default? :-)

I am using expo-cli to run application on the mobile (Android) over USB and expo provides me with a console on a terminal that I start it from. Would Debugger work in that configuration or only for web applications? By the way I am working on Android connected to USB on macOS that I connect to over SSH from my FreeBSD. I cannot really use clear react-native run-android at it is spawned in another terminal that is not forwarded by X so I can see nothing on my FreeBSD until I sit in front of a macOS build machine (as opposed to expo run:android that gives me all details directly in a terminal it was spawned from also SSH. I did the port forwarding and I can access stuff from macOS on my FreeBSD.. but it looks the same as on the local macOS access.

From a Debugger I would expect to see the code flow, threads, memory map, variable state and values, alter GUI state along with other components, set breakpoints and watchpoints, etc etc etc. When entering that "debug website" I can not even see source code of my application under development, just the website itself.

Maybe I am doing something wrong? Is this Debugger just a tricky name or there is a real Debugger behind it (lets say like GDB)? What are the features of available Debugger (I have found no list) and what more it gives me than expo-cli? :-)

@aprilmintacpineda
Copy link

What about errors with no stack like this one?

image

facebook/react-native#32044

Working code in react-native 0.64.2, I tried upgrading to react-native 0.65.1 then I got that error but it looks like a dead-end for me because I can't find any lead other than the upgrade so it must be something in react-native 0.65 or maybe one of my dependencies? I don't know, don't even know where to look... I've stuck in this problem for 16 days now and can't upgrade because of it.

@gwmccull
Copy link

gwmccull commented Sep 4, 2021

@cederom I don't use any logging libraries so I can't recommend anything there

I haven't really used Expo but according to their docs, you can use the Chrome debugger. It's a full debugger with the ability to see variables and step through code. This blog also provides some additional info about interacting with the Chrome debugger. Although, one thing that I didn't see mentioned that I believe you can use is to enable "pause on caught exceptions" and then use a debugger statement in your code to cause Chrome to stop and open to the correct file. This is the same technique used to debug any other JS so you can Google and find resources about that

@aprilmintacpineda I don't know what causes that error. If it were me, I would try basically commenting out the entire app (including all of the imports) except for a single View and see if the error goes away. If it does, then start commenting stuff in until you reproduce the error and narrow it down from there. It's a giant pain but it should help narrow down the location. That's assuming you've already tried Googling the error, of course

@sreekanth-14
Copy link

Hi Everyone,

If anyone knows a solution for the below issue. Please let me know. Because most of the crashes in our playconsole are related to this bug only. But we could not know what it is. Everyone is talking about arm based cpu architectures. So please explain in detail if you guys know.

Bug:

SIGSEGV · Segmentation violation (invalid memory reference)

/data/data/in.onecode.app/lib-0/libjsc.so:1013576 0x74949b1748

/data/data/in.onecode.app/lib-0/libjsc.so:1327084 0x74949fdfec

/data/data/in.onecode.app/lib-0/libjsc.so:1241260 0x74949e90ac

/data/data/in.onecode.app/lib-0/libjsc.so:1283208 0x74949f3488

@jamonholmgren
Copy link
Collaborator

Update to the promise rejection debugging experience with React Native 0.66.4:

image

Prettier, but still doesn't give useful debugging info as to what was thrown and where it occurred.

This is still something that affects us daily, so I'd love to see improvement to this experience.

Ref: #69 (comment)

Note that using function component syntax doesn't change the result, if anyone was wondering:

import React, {useEffect} from 'react';
import {Text, View} from 'react-native';

export default function App() {
  useEffect(() => {
    async function crash() {
      throw new Error('crashed');
    }
    crash();
  });

  return (
    <View>
      <Text>Jamon</Text>
    </View>
  );
}

@ajenkins
Copy link

ajenkins commented Jun 2, 2022

I hit this error in my application: Error: Text strings must be rendered within a <Text> component.

But the stack trace is completely unhelpful:
IMG_1252B4AC6F5A-1

This is the stack trace that I see when the error is logged to Sentry, and makes it very hard to figure out where this error is coming from.

However, I noticed that when I'm running my app locally, there's a much more helpful "trace" in my console. It looks like this:

Error: Text strings must be rendered within a <Text> component.

This error is located at:
    in RCTView (created by View)
    in View (created by Profile)
    in RCTScrollContentView (created by ScrollView)
    in RCTScrollView (created by ScrollView)
    in ScrollView (created by ScrollView)
    in ScrollView (created by Profile)
    in Profile (created by ViewProfile)
    in ViewProfile (created by SceneView)
    in StaticContainer
    in EnsureSingleNavigator (created by SceneView)
    in SceneView (created by SceneView)
    in RCTView (created by View)
    in View (created by DebugContainer)
    in DebugContainer (created by MaybeNestedStack)
    in MaybeNestedStack (created by SceneView)
    in RNSScreen (created by AnimatedComponent)
    in AnimatedComponent
    in AnimatedComponentWrapper (created by Screen)
    in MaybeFreeze (created by Screen)
    in Screen (created by SceneView)
    in SceneView (created by NativeStackViewInner)
    in RNSScreenStack (created by ScreenStack)
    in ScreenStack (created by NativeStackViewInner)
    in NativeStackViewInner (created by NativeStackView)
    in RCTView (created by View)
    in View (created by SafeAreaInsetsContext)
    in SafeAreaProviderCompat (created by NativeStackView)
    in NativeStackView (created by NativeStackNavigator)
    in Unknown (created by NativeStackNavigator)
    in NativeStackNavigator (created by MyProfileNavigator)
    in MyProfileNavigator (created by SceneView)
    in StaticContainer
    in EnsureSingleNavigator (created by SceneView)
    in SceneView (created by BottomTabView)
    in RCTView (created by View)
    in View (created by Screen)
    in RCTView (created by View)
    in View (created by Background)
    in Background (created by Screen)
    in Screen (created by BottomTabView)
    in RNSScreen (created by AnimatedComponent)
    in AnimatedComponent
    in AnimatedComponentWrapper (created by Screen)
    in MaybeFreeze (created by Screen)
    in Screen (created by MaybeScreen)
    in MaybeScreen (created by BottomTabView)
    in RNSScreenNavigationContainer (created by ScreenContainer)
    in ScreenContainer (created by MaybeScreenContainer)
    in MaybeScreenContainer (created by BottomTabView)
    in RNCSafeAreaProvider (created by SafeAreaProvider)
    in SafeAreaProvider (created by SafeAreaInsetsContext)
    in SafeAreaProviderCompat (created by BottomTabView)
    in BottomTabView (created by BottomTabNavigator)
    in Unknown (created by BottomTabNavigator)
    in BottomTabNavigator (created by MainNavigator)
    in MainNavigator (created by AppWithNavigation)
    in EnsureSingleNavigator
    in BaseNavigationContainer
    in ThemeProvider
    in NavigationContainerInner (created by AppWithNavigation)
    in AppWithNavigation (created by AppWithProviders)
    in AppWithProviders (created by App)
    in AnalyticsProvider (created by App)
    in UserProvider (created by App)
    in App (at Auth/index.tsx:106)
    in Wrapper (created by ExpoRoot)
    in ExpoRoot
    in RCTView (created by View)
    in View (created by AppContainer)
    in RCTView (created by View)
    in View (created by AppContainer)
    in AppContainer
    in main(RootComponent)
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:95:4 in reportException
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:141:19 in handleException
at node_modules/react-native/Libraries/Core/setUpErrorHandling.js:24:6 in handleError
at node_modules/expo-dev-launcher/build/DevLauncherErrorManager.js:44:19 in errorHandler
at node_modules/expo-dev-launcher/build/DevLauncherErrorManager.js:49:24 in <anonymous>
at node_modules/expo-error-recovery/build/ErrorRecovery.fx.js:12:21 in ErrorUtils.setGlobalHandler$argument_0

There are no line numbers, which is unfortunate, but at least it tells you which component the error is coming from. It would be great to have this type of information in the actual stack trace. It's very confusing when there's an error in my code, but the stack trace doesn't include a single line of my own code.

@shamilovtim
Copy link

Lately I am receiving completely unactionable stack traces around promises. It has never been as bad as it is now. No line number, no calling function, nothing. Just lots and lots of generator -> asyncFoo -> generator -> try -> reject -> etc etc. Is there a reason promise stacktraces are so broken in RN?

@BasixKOR
Copy link

BasixKOR commented Jun 5, 2023

How's the symbol publication for Hermes going? I know not a large number of people would be affected by this, but for those who are affected, it's a night and day difference.

Opening a tracking issue would be nice but I didn't open one since I wasn't quite sure which repository I should be posting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🗣 Discussion This label identifies an ongoing discussion on a subject
Projects
None yet
Development

No branches or pull requests