react-native: XHR fails with "Invalid response for blob" on Android

React crash on fetch, Android only Similar to https://github.com/facebook/react-native/issues/18223 (but this is only ios) Similar to https://github.com/facebook/react-native/issues/18190 (but my response is not empty and the response code is 200)

Environment

Environment: OS: macOS High Sierra 10.13.3 Node: 9.6.1 Yarn: 1.5.0 npm: 5.6.0 Watchman: 4.9.0 Xcode: Xcode 9.2 Build version 9C40b Android Studio: 3.0 AI-171.4443003

Packages: (wanted => installed) react: 16.2.0 => 16.2.0 react-native: 0.54.0 => 0.54.0

Steps to Reproduce

that’s enough to crash on Android (it works all right on ios) Emulated on google Pixel android 27

fetch(https://crypto-viewer.rebeleo.com/updates/en-US/android) .then(res => res.json()) .then(data => ({ data })) .catch(err => { alert('Something went wrong with the Updatesfeed 😦 => ’ + err) return { err } })

Expected Behavior

Expect the type of the response to be seen as json

Actual Behavior

This is a regression issue. The response is seen as empty, and as blob

screenshot_1521418646

// Is going in this branch case ‘blob’: if (typeof this._response === ‘object’ && this._response) { this._cachedResponse = BlobManager.createFromOptions(this._response); } else { throw new Error(Invalid response for blob: ${this._response}); } break;

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 21
  • Comments: 79 (25 by maintainers)

Most upvoted comments

@tmaly1980: Why is this still a problem when there’s a clear solution?

Because nobody has provided a way to reproduce this bug and there’s no way to test whatever fix we do actually works.

@satya164

Here is a repro:

https://github.com/TheSavior/react-native-blob-repro

The relevant lines are the server:

app.post('/', (req, res) => res.end('', 'binary'));

and the react-native app:

fetch('http://localhost:8798', {method: 'POST'});

@wadim that fixes it on iOS - but the issue remains on 0.55.4 on Android, which I’m currently running.

Sure thing, I will create it soon

We’re using CodePush as well and this is a critical bug preventing us from deploying with 0.55. I’ve lobbied for the JS fix which improves the robustness of blob handling. Until that’s merged, use a postinstall script to patch it as so in the package.json:

  "scripts": {
    "postinstall": "rn-patches/apply-patches.sh"
  },

And the apply-patches.sh script:

#!/bin/bash
# Critical patches for RN 0.55

# Fix "Invalid response for blob" with fetch https://github.com/facebook/react-native/issues/18223
curl -O https://github.com/xiamx/react-native/commit/b35071b5daabf370e7789e00e1593788fcf5aecf.patch
patch $PWD/node_modules/react-native/Libraries/Network/XMLHttpRequest.js b35071b5daabf370e7789e00e1593788fcf5aecf.patch
rm -f b35071b5daabf370e7789e00e1593788fcf5aecf.patch

PS: some folks asked about how to resolve this so posted here to help others.

@psegalen No, the issue with CodePush is that I have my wifi/data turned off (as a part of testing my app’s offline mode), so it’s not able to connect to the server and gets an empty response. I believe it’s asking for a binary file so that might explain the ‘blob’ part. Has nothing to do with SSL certificates in my case.

Regardless, the code should be able to handle an empty/invalid response without crashing the app. At least with the case of CodePush, the request lifecycle is not something I have control over (ie the fetch code is so deeply buried in 3rd party code), so I can’t put everything into a try/catch to ignore the error.

@satya164 unfortunately for now it isn’t a repro at all since it’s functional, I’m working on making it a repro

@shashank19909 with 0.56.0 on android I am no longer getting “Invalid response on blob”, however I am getting a “Network request failed” red screen of death when hitting an intentionally offline API endpoint. I would expect to be able to catch that error in my code.

screenshot-2018-08-08_22 04 33 732

Guess I’ll bump this again. This issue is still on all versions for Android. iOS fixed but Android not so much.

@satya164 I’m beginning to wonder if it’s not something form the server, I’ll dig deeper tomorrow, when my repro uses a GraphQL server from Microsoft everything’s fine but when I try to make it query my server it fails with a Network error… 😕 Same test on iOS works just fine… I’ll hunt for a particular header / encoding we would be using… tomorrow!

@satya164 It’s actually pretty easy if you have a project that uses code-push. Just turn off your dev machine’s network connection and then reload the code-push enabled app. It’ll trigger that error because the fetch to query for updates fails and has no content to return.

FWIW I’m still getting this on on 55.3 for Android, but only if I have my WiFi disconnected. I’m also using bugsnag and it could potentially be related to the blob being null or something/network request failing. If I am connected to WiFi it seems to work. This issue is also being tracked here: https://github.com/react-native-community/react-native-releases/issues/11

@satya164 I just tried to reproduce the error and got nothing here it is, maybe it can save someone some time : link

tell me if I can provide you with any further help or informations

(the api key provided in the repo for bugsnag is a “junk” one, don’t worry)

peacechen: It sounds like you don’t trust us, which quite frankly is insulting

Take it personally if you will. But as a professional, you should know better than treating causes than fixing the symptoms.

we shouldn’t be throwing there because it isn’t an error caused by the developer

It’s likely that the error happens because of some incorrect code on the native side. In iOS, there was some incorrect handling of response which was found because of this error. Suppressing the error doesn’t fix the issue and might also hide other bugs in the native code. Also, this error doesn’t happen on iOS with the same exact JS code, which means that the bug is most likely in the native code, not in JS.

Anyway, this code path shouldn’t be called unless there’s a bug in native side, which I want to fix.

Returning null seems to make the most sense as that is what is done for other issues that are from the server response

Don’t know what issues you’re referring to, but it should behave the same as browser. If server gives a bad response, browser will trigger the error handler and we should do the same instead of ignoring any errors. It’s probably a bug in the code than bad server response.

Regardless of a repro, we shouldn’t be throwing there because it isn’t an error caused by the developer and there is no way for it to be handled by the developer. A bad server response will crash the app.

Returning null seems to make the most sense as that is what is done for other issues that are from the server response.

Do you agree or disagree with this approach?

The bug on latest android 0.55.4 … @CapitanRedBeard . For me , non server connection is a test also. Empty respond also need to check but since the red page appear first… It is bug.Long time ago i complain, can we get real status XHR like 400,404,200.

@tmaly1980 maybe CodePush server has SSL issue? If you have the host name, give the ssllabs tool a go, if the grade isn’t A, it may be the source of the problem! @hmenzagh maybe the same applies to the BugSnag server? @obsidianart could be your problem too?

@satya164 I made several tests on my code and failed to fix the bug in RN Android code for now, I don’t have enough time because of some iOS deadlines for my app. Interestingly, I was just about to share a repro with you but the Android app of my repro is actually functional! 😂 I’ll try to downgrade RN to my real code version to see if the error is there.

throwing an exception in this case is the worst action because it’s difficult or impossible to catch the error

It is a “BUG”. There shouldn’t be any error. The only case that condition will be executed was if there was a bug. The user “shouldn’t” need to handle this. It’s not any different from other places where we throw runtime exception which crashes the app. The library doesn’t know how to handle an inconsistent state and hence throws an error.

If we had silenced the error from the beginning, we’d probably have never known that there is a bug in the code, and even when we did, would’ve been way harder to know what part of the code has the bug. Do you see why silencing the error is not a good idea?

If temporarily silencing the error works for you, great. You can temporarily fork it while the root cause it fixed. But it’s not a fix, it’s an workaround.

vote for the JS fix

Seriously?

@peacechen this fix doesn’t fix anything, it masks the issue. I use react-apollo and the “fix” only moves the crash to the next instructions in the pipeline: the lib wants to exploit the result of the request which is null… result is a network error… 😦

I need an isolated repro.

There is a well tested fix at https://github.com/xiamx/react-native/commit/b35071b5daabf370e7789e00e1593788fcf5aecf

@petarjs Forking the repo doesn’t work because RN has native code that needs to be built. FB does this during the release process and includes those binary bits in the npm release.

@petarjs unfortunately, I want the blob returned by the server 😢 I’m working on a fix currently, hopefully I’ll do a PR soon.

Just for the sake of reporting (I’m not making a repro for this), I get the same error while running the debug build of my app (RN 0.54.4) on a real Android device (while connected to my Mac on USB) that happens to be out of network connection, such as being in airplane mode. The redbox apparently appears while trying to fetch http://localhost:8081/symbolicate (not sure), so there’s nothing I can do to stop it.

Same error in Android app using RN 0.55.1