question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Native error is thrown when blob is read with FileReader.readAsDataURL

See original GitHub issue

Description

I’m using FileReader.readAsDataURL to consume a Blob returned by RN’s networking layer as an ArrayBuffer to implement FileReader.readAsArrayBuffer (https://github.com/facebook/react-native/issues/21209) and it has been working just fine, at least with the data I’ve been processing.

I’m working on an implementation of the Fetch API for RN where the underlying response is always a ReadableStream (so Response.body can be implemented at all times). All chunks of the stream are Uint8Arrays and the only way at the moment to convert a Blob to an ArrayBuffer is through FileReader.readAsDataURL.

However, when I use console.error or console.warn on iOS (didn’t test on Android yet), the error shown in the image below is occurring.

image

React Native version:

System:
    OS: macOS 10.15.6
    CPU: (4) x64 Intel(R) Core(TM) i7-7567U CPU @ 3.50GHz
    Memory: 427.45 MB / 16.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 14.7.0 - /usr/local/bin/node
    Yarn: 1.15.2 - /usr/local/bin/yarn
    npm: 6.14.7 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.9.1 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 14.1, DriverKit 19.0, macOS 10.15, tvOS 14.0, watchOS 7.0
    Android SDK:
      API Levels: 25, 28, 29
      Build Tools: 28.0.3, 29.0.2
      System Images: android-28 | Google Play Intel x86 Atom
      Android NDK: Not Found
  IDEs:
    Android Studio: 3.5 AI-191.8026.42.35.6010548
    Xcode: 12.1/12A7403 - /usr/bin/xcodebuild
  Languages:
    Java: 1.8.0_201 - /usr/bin/javac
    Python: 3.8.5 - /usr/local/opt/python@3/libexec/bin/python
  npmPackages:
    @react-native-community/cli: Not Found
    react: ^16.9.0 => 16.9.0
    react-native: ^0.63.3 => 0.63.3
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps To Reproduce

Provide a detailed list of steps that reproduce the issue.

Given any app, patch Body.text() in node_modules/whatwg-fetch/dist/fetch.umd.js as follows:

this.text = async function() {
   var rejected = consumed(this);
   if (rejected) {
      return rejected
   }

   if (this._bodyBlob) {
	  function readBlobAsDataURL(blob) {
         var reader = new FileReader();
         var promise = fileReaderReady(reader);
         reader.readAsDataURL(blob);
         return promise
      }

      const { toByteArray } = require('base64-js');
      const { TextDecoder } = require('text-encoding'); // needs to be installed
      const dataURL = await readBlobAsDataURL(this._bodyBlob);
      const base64 = dataURL.split(',')[1];

      return new TextDecoder().decode(toByteArray(base64));
   } else if (this._bodyArrayBuffer) {
      return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
   } else if (this._bodyFormData) {
      throw new Error('could not read FormData body as text')
   } else {
      return Promise.resolve(this._bodyText)
   }
};

Then, call console.error or console.warn.

Expected Results

I expect to be able to consume a Blob as a data URL without any error being thrown.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:3
  • Comments:7

github_iconTop GitHub Comments

5reactions
mcraigiecommented, Apr 10, 2021

in case @menssen’s workaround wasn’t clear, you can silence the error by manually setting a data type:

fetch(src)
  .then(res => res.blob())
  .then(blob => {
    // https://github.com/facebook/react-native/issues/30378
    blob.data.type = 'image/jpeg';

    var reader = new FileReader();

    reader.readAsDataURL(blob);

    reader.onloadend = () => {
      var base64data = reader.result;

      console.log(base64data);
    };
  })
  .catch(e => console.error(e));

The problem being that the type information at the start of your base64 string will be whatever you set it to, not whatever the blob actually contained. Could be fine if you always know what kind of data you will be dealing with.

This kind of thing really isn’t my wheelhouse either, but you might be able to determine/repair the type information using something like:

https://github.com/sindresorhus/file-type

2reactions
menssencommented, Nov 22, 2020

Ran into the same problem today.

I’m relatively sure the problem is here:

https://github.com/facebook/react-native/blob/master/Libraries/Blob/RCTFileReaderModule.mm#L71

There is a null check for “type” on the subsequent line (defaulting it to application/octet-stream), but it actually should be prior to the RCTConvert, since that may fail if it is null and spit out an error.

So in other words, I think this:

    NSString *type = [RCTConvert NSString:blob[@"type"]];
    NSString *text = [NSString stringWithFormat:@"data:%@;base64,%@",
                      type != nil && [type length] > 0 ? type : @"application/octet-stream",
                      [data base64EncodedStringWithOptions:0]];

Should be something like:

    NSString *blobType = blob[@"type"] != nil && [blob[@"type"] length] > 0 ? blob[@"type"] : @"application/octet-stream";
    NSString *type = [RCTConvert NSString:blobType];
    NSString *text = [NSString stringWithFormat:@"data:%@;base64,%@",
                      type,
                      [data base64EncodedStringWithOptions:0]];

I hacked around it by just setting blob.data.type to something manually before calling readAsDataURL.

I’d try to submit a PR, but this is like my fourth day touching either React Native or ObjC, so somebody else should probably take it from here.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Uncaught TypeError: Failed to execute 'readAsDataURL' on ...
I've got a problem with a javascript Filereader which returns the error Uncaught TypeError: Failed to execute 'readAsDataURL ...
Read more >
FileReader.readAsDataURL() - Web APIs | MDN
The readAsDataURL method is used to read the contents of the specified Blob or File. When the read operation is finished, the readyState ......
Read more >
File API - W3C
This specification defines an asynchronous API based on an event model to read and access a File or Blob 's data. A FileReader...
Read more >
PI44703: A HYBRID APP MAY FAIL TO UPLOAD A FILE ... - IBM
A hybrid app may fail to upload a file using a native FileReader and ... from the native Android file read returns a...
Read more >
cordova-plugin-file
file.* properties defined for iOS (only applicationDirectory and applicationStorageDirectory are read-only). FileReader.readAsText(blob, encoding).
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found