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.

Illegal callback invocation from native module error

See original GitHub issue

Description

After upgraded to 0.41, many modules don’t work and get this error:

java.lang.RuntimeException: Illegal callback invocation from native module. This callback type only permits a single invocation from native code.
at com.facebook.react.bridge.CallbackImpl.invoke(CallbackImpl.java:32)

I think it’s caused by this change in react-native which limits the callback to be invoked for only once:

Fail-Fast on Redundant Java Callback Invocations

  @Override
  public void invoke(Object... args) {
+    if (mInvoked) {
+      throw new RuntimeException("Illegal callback invocation from native "+
+        "module. This callback type only permits a single invocation from "+
+        "native code.");
+    }
    mCatalystInstance.invokeCallback(mExecutorToken, mCallbackId, Arguments.fromJavaArgs(args));
+    mInvoked = true;
  }

However, many modules would expect their callbacks to be invoked more than once. E.g. react-native-dialogs which shows native dialogs for Android. And on the dialog, we will probably invoke the callback for multiple times, e.g. select an option, press ok will both invoke the callback with different args.

Have we considered that sometimes we do need multiple callback invocations?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:7
  • Comments:9

github_iconTop GitHub Comments

5reactions
pwcremincommented, Oct 3, 2017

Instead of using callbacks, use events with RCTEventEmitter

Example below using swift. I left out the .m since it isn’t relevant to event emitting with swift. The obj-c version is about the same and will be easy for you to google/figure out

edit: I put together a small blog post to explain this: https://medium.com/nycdev/calling-a-callback-multiple-times-in-a-react-native-module-5c3c61f2fca4

.swift

@objc(RNSpeechToText)
class RNSpeechToText: RCTEventEmitter {
  
  var speechToText: SpeechToText?
  var audioPlayer = AVAudioPlayer()
  var hasListeners = false
  
  static let sharedInstance = RNSpeechToText()
  
  private override init() {}
  
  override func supportedEvents() -> [String]! {
    return ["StreamingText"]
  }
  
  @objc func initialize(_ username: String, password: String) -> Void {
    speechToText = SpeechToText(username: username, password: password)
  }
  
  @objc func startStreaming(_ errorCallback: @escaping RCTResponseSenderBlock) {
    
    var settings = RecognitionSettings(contentType: .opus)
    settings.interimResults = true
    
    let failure = { (error: Error) in errorCallback([error]) }
    
    speechToText?.recognizeMicrophone(settings: settings, failure: failure) { results in
      if(self.hasListeners)
      {
        self.sendEvent(withName: "StreamingText", body: results.bestTranscript)
      }
    }
  }
  
  @objc func stopStreaming() {
    speechToText?.stopRecognizeMicrophone()
  }
  
  override func startObserving()
  {
    hasListeners = true
  }
  
  override func stopObserving()
  {
    hasListeners = false
  }
}

.js

import { NativeEventEmitter, NativeModules } from 'react-native';

let {
    RNSpeechToText
} = NativeModules

module.exports = {
SpeechToText: {
        speechToTextEmitter: new NativeEventEmitter(RNSpeechToText),

        initialize: function ( username, password )
        {
            RNSpeechToText.initialize( username, password );
        },

        startStreaming(callback)
        {
            this.subscription = this.speechToTextEmitter.addListener(
                'StreamingText',
                (text) => callback(null, text)
            );

            RNSpeechToText.startStreaming(callback)
        },

        stopStreaming()
        {
            this.subscription.remove()

            RNSpeechToText.stopStreaming()
        }
    }
}
1reaction
dobrienlzdcommented, May 5, 2017

Ok, here is the answer for now: Whenever you invoke a method from the javascript side on the module that may in turn invoke the callback you need to reset the callback:

resetCallback(){ MyModule.setTheCallback((value) => { this.setState({ value: value }); }); } invokeMethodThatMayInvokeCallback(){ resetCallback(); MyModule.bar(); // the method within the module that will invoke the callback. }

Read more comments on GitHub >

github_iconTop Results From Across the Web

App crash with error: Illegal callback invocation from native ...
App crash with error : Illegal callback invocation from native module. This callback type only permits a single invocation from native code. #713....
Read more >
React Native callback type only permits a single invocation ...
I am getting "Illegal callback invocation from native module. This callback type only permits a single invocation from native code." 3 · Getting ......
Read more >
Calling a callback multiple times in a React Native module
You wanted a callback to be invoked multiple times, but got this error instead "Illegal callback invocation from native module.
Read more >
Android Native Modules
Another important detail to note is that a native module method can only invoke one callback, one time. This means that you can...
Read more >
Getting "Illegal callback invocation from native module. This ...
[Solved]-Getting "Illegal callback invocation from native module. This callback type only permits a single invocation from native code"-React Native.
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