Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Malformed calls from JS: field sizes are different

Tags:

react-native

I get an error when I run the ios simulator. As soon as I login, the app crashes.

I was on the branch master, everything was working fine. I created a new branch 'android' and ran the android simulator, fixing a few things related to android. Then I wanted to make sure things still looked good in iPhone, so I ran to iPhone simulator and that's when I got the bug. The screen does not crash immediately. It crashes as soon as I login. The android simulator runs perfectly fine though. I figured I would 'git checkout master' branch to pinpoint what exactly caused that error, but the error persisted on the master branch. That doesn't make much sense to me.

This is my stacktrace:

Malformed calls from JS: field sizes are different.

[[74,24],[19,1],[[64,2000,1552169087432,false]],415]

RCTFatal
-[RCTCxxBridge handleError:]
__34-[RCTCxxBridge _initializeBridge:]_block_invoke
facebook::react::RCTMessageThread::tryFunc(std::__1::function<void ()> const&)
facebook::react::RCTMessageThread::runOnQueue(std::__1::function<void ()>&&)::$_1::operator()() const
void std::__1::__invoke_void_return_wrapper::__call<facebook::react::RCTMessageThread::runOnQueue(std::__1::function<void ()>&&)::$_1&>(facebook::react::RCTMessageThread::runOnQueue(std::__1::function<void ()>&&)::$_1&&&)
std::__1::__function::__func<facebook::react::RCTMessageThread::runOnQueue(std::__1::function<void ()>&&)::$_1, std::__1::allocator<facebook::react::RCTMessageThread::runOnQueue(std::__1::function<void ()>&&)::$_1>, void ()>::operator()()
std::__1::function<void ()>::operator()() const
invocation function for block in facebook::react::RCTMessageThread::runAsync(std::__1::function<void ()>)
CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK
__CFRunLoopDoBlocks
__CFRunLoopRun
CFRunLoopRunSpecific
+[RCTCxxBridge runRunLoop]
NSThread__start
_pthread_body
_pthread_body
thread_start

I have no idea how to debug this issue. It came out of nowhere and reverting to previous commits isn't helping. The error details don't give me much to work with. Please help!

Here are my package.json dependencies:

"@babel/core": "^7.3.3",
"antd-mobile-rn": "^2.2.1",
"axios": "^0.18.0",
"babel-eslint": "^8.2.2",
"bugsnag-react-native": "^2.14.0",
"bugsnag-sourcemaps": "^1.1.0",
"moment": "^2.24.0",
"node": "^10.15.1",
"npm": "^6.7.0",
"prop-types": "^15.6.1",
"react": "^16.7.0",
"react-native": "^0.58.4",
"react-native-alert-async": "^1.0.3",
"react-native-aws3": "0.0.8",
"react-native-cached-image": "^1.4.3",
"react-native-country-picker-modal": "^0.7.1",
"react-native-elements": "^0.19.0",
"react-native-modalbox": "^1.7.1",
"react-native-photo-upload": "^1.3.0",
"react-native-push-notification": "^3.1.2",
"react-native-router-flux": "^4.0.0-beta.28",
"react-native-step-indicator": "0.0.9",
"react-native-swiper": "^1.5.14",
"react-native-vector-icons": "^4.6.0",
"react-navigation": "^2.18.3",
"rn-fetch-blob": "^0.10.15",
"socks": "^2.3.0",
"tinycolor2": "^1.4.1"

Let me know what additional information I can provide.

like image 252
Rony Azrak Avatar asked Mar 10 '19 04:03

Rony Azrak


2 Answers

This a very generic (and complex) error and there could be a number of reasons behind it, so I'll post 2 ways of trouble shooting this one, an easy one that "may" work, and a harder one that will "definitely" work.

Easy method (may not work):

Eliminating the low hanging fruit first (NaN, Infinity issues):

  • Step 1: Copy the full error message, paste it on a text editor, maybe even beautify it with something like https://beautifier.io/

  • Step 2: Search for the string NaN, or the string Infinit.

If you're lucky you'll notice that you're probably accidentally passing a NaN value as a component style, or a component prop. Fixing that value will fix the issue. How you'll figure out which component or style that is, you'll check the information around the NaN value. (i.e you pass a fontName: 'whatever' on that same style, and that gives away where the issue is)

The complex one (will work):

Why that error is thrown - along with some context:

(if you don't care about the context you can jump directly to the "How to troubleshoot" section)

As you probably know, react-native used to use the react-native bridge to pass information over to the native side. To do that it uses a very weird format of arrays, so let's look at the error above:

[
    [74, 24],
    [19, 1],
    [
        [64, 2000, 1552169087432, false]
    ], 415
]

This is a batched bridge message, which basically means, a series of messages were sent over the bridge (because react-native batches them to save resources).

The first array contains the module ids that were called

The second array contains the module method ids that were called

The third array contains the params those methods were given.

In the example above the module 74 called the method 19 and was given params [64, 2000, 1552169087432, false]

The problem can be identified easily here since the second call module 24, which called method 1 was expecting params but nothing was passed as params to it. For the call to be correct the third array should contain another child (like so:

[
    [74, 24],
    [19, 1],
    [
        [64, 2000, 1552169087432, false],
        [] // <-- that was missing
    ], 415
]

Thus the field sizes are different error. That's because react-native expects that for every given call, all 3 fields should contain information.

The reason params were missing is because one of our modules didn't like one of our inputs (specifically the parameter type we were passing) and decided to crash silently. Our app didn't crash but wrong information was sent over the bridge.

That being said, all we must do now is figure out where the problem is:

How to troubleshoot (solution):

To figure out who the troublemaker module is, we'll go through all of the message method calls that were sent via the bridge in the above batched message (as indicated in our crash log).

What we'll be doing:

Using the above issue as an example. To resolve that we need to figure out which module the module with id 74 is (module name), and what the method name the method with id 19 is (method name).

Then we'll repeat the same process for every sequence of calls seen in our crash report.

i.e module with id 24, method with id 1

The goal here is to figure out which native module and method called caused the crash, and since all RN native module calls pass through the bridge we can achieve that quite easily.

All we need now is a way to convert those id's to actual module names, and method names. We're in luck, because react-native exposes that information via the BatchedBridge. When a module is created (typically when the app launches) react-native keeps a reference of the module id's and method id's. We'll take advantage of that to get the module/method names we need.

Steps:

Step 1: Add the following code snippet anywhere in your code:

if (global.__fbBatchedBridge) {
  const origMessageQueue = global.__fbBatchedBridge;
  const modules = origMessageQueue._remoteModuleTable;
  const methods = origMessageQueue._remoteMethodTable;
  global.findModuleByModuleAndMethodIds = (moduleId, methodId) => {
    console.log(`The problematic line code is in: ${modules[moduleId]}.${methods[moduleId][methodId]}`)
  }
}

Step 2: All you have to do now is set a breakpoint anywhere in your app, and try the pairs of module/method id's as parameters of the global.findModuleByModuleAndMethodIds function like so:

global.findModuleByModuleAndMethodIds(74, 19);
global.findModuleByModuleAndMethodIds(24, 1);

and that will print the suspects names. From there on you'll be in a much better position to figure out what went wrong.

For example, the first call may print something like: Timing.createTimer (which is a typical message react-native sends when we setTimeout and may not be related to your crash.

Step 3: Investigate each of those calls, and look for wrong/weird parameters, you pass to those native functions.

For me one of the calls output: RNFBAnalyticsModule.logEvent which made me investigate how we logged events to firebase (right at the time of the crash) only to find out that we were passing a moment as one of it's props. Firebase didn't like that and silently crashed, causing the above error.

I hope that saves hours of headache to someone - I spent hours to discover all of the above.

like image 83
SudoPlz Avatar answered Sep 19 '22 14:09

SudoPlz


I think it happened when you pass NaN or something Infinity to the native bridge. In my code, it will be like below:

class MyComponent extends React.Component 
  constructor() {
    // wrong retrun value from `foo()`, this.myProperty will be `Infinity`
    this.myProperty = foo();
  }

  // Component methods here....


  myFancyFunction() {
    // This code will encounter `Malformed calls from JS: field sizes are different`
    // `[xxxx, "<<Infinity>>", xxxxxxxxx, true]`
    this.timer = setInterval(() => {
      //Do something
    }, this.myProperty); //<-- should never be `Infinity` here
  }
}

A lot thanks to this link: #23835

like image 29
uspython Avatar answered Sep 16 '22 14:09

uspython