react-native-dialogs: RuntimeException: This callback type only permits a single invocation from native code.

I am experiencing these two exceptions after I migrated to the latest version i.e. 1.0.1. The errors occur either in the process of showing an alert or when clicking one of the buttons in the alert. There are two callstacks seen on Sentry. Below is the code that I am using to show the alert. I thought one of the goals of the overhaul of the API was to get rid of multiple invocation errors. Please let me know how can I fix this problem. It is not happening in my debug environment due to which I am not able to run it in debugger.

const showAlert = async (title, message, buttons, cancelable = true) => {
      const validButtons = buttons ? buttons.slice(0, 3) : [{text: I18n.t('ok')}];
      const buttonPositive = validButtons.pop();
      const buttonNegative = validButtons.pop();
      const buttonNeutral = validButtons.pop();

      const options = {
        title: title && title !== '' ? title : undefined,
        content: message && message !== '' ? message : undefined,
        positiveText: buttonPositive ? buttonPositive.text :  undefined,
        positiveColor: buttonPositive && buttonPositive.style && buttonPositive.style === 'destructive' ? colorThemes.Blue.red : colorThemes.Blue.primary,
        negativeText: buttonNegative ? buttonNegative.text :  undefined,
        negativeColor: buttonNegative && buttonNegative.style && buttonNegative.style === 'destructive' ? colorThemes.Blue.red : colorThemes.Blue.primary,
        neutralText: buttonNeutral ? buttonNeutral.text :  undefined,
        neutralColor: buttonNeutral && buttonNeutral.style && buttonNeutral.style === 'destructive' ? colorThemes.Blue.red : colorThemes.Blue.primary,
        cancelable: cancelable
      }
      const { action } = await DialogAndroid.alert(title, message, options);
      switch (action) {
        case DialogAndroid.actionPositive:
            buttonPositive && buttonPositive.onPress && buttonPositive.onPress()
            break;
        case DialogAndroid.actionNegative:
            buttonNegative && buttonNegative.onPress && buttonNegative.onPress()
            break;
        case DialogAndroid.actionNeutral:
            buttonNeutral && buttonNeutral.onPress && buttonNeutral.onPress()
            break;
        case DialogAndroid.actionDismiss:
            break;
      }
  }
RuntimeException
Illegal callback invocation from native module. This callback type only permits a single invocation from native code.
com.facebook.react.bridge.CallbackImpl in invoke at line 28
com.aakashns.reactnativedialogs.modules.DialogAndroid$4 in onClick at line 240
com.afollestad.materialdialogs.MaterialDialog in onClick at line 396
android.view.View in performClick at line 6897
android.widget.TextView in performClick at line 12653
android.view.View$PerformClick in run at line 26097
android.os.Handler in handleCallback at line 789
android.os.Handler in dispatchMessage at line 98
android.os.Looper in loop at line 164
android.app.ActivityThread in main at line 6940
Called from: java.lang.reflect.Method in invoke
com.android.internal.os.Zygote$MethodAndArgsCaller in run at line 327
com.android.internal.os.ZygoteInit in main at line 1374
RuntimeException
Illegal callback invocation from native module. This callback type only permits a single invocation from native code.
com.facebook.react.bridge.CallbackImpl in invoke at line 28
com.aakashns.reactnativedialogs.modules.DialogAndroid$11 in onDismiss at line 351
android.app.Dialog$ListenersHandler in handleMessage at line 1503
android.os.Handler in dispatchMessage at line 105
android.os.Looper in loop at line 164
android.app.ActivityThread in main at line 6940
Called from: java.lang.reflect.Method in invoke
com.android.internal.os.Zygote$MethodAndArgsCaller in run at line 327
com.android.internal.os.ZygoteInit in main at line 1374

About this issue

Commits related to this issue

Most upvoted comments

Using import { Alert } from 'react-native'; instead. That worked šŸŽ‰

Hi, is there any solution to this? I’m also getting this error!

with this simple line of code: DialogAndroid.alert('Error', An error occured: ${reason}.);

2019-11-04 09:13:24.855 23951-23951/com.strimmobile.uat E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.strimmobile.uat, PID: 23951
    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:25)
        at com.aakashns.reactnativedialogs.modules.DialogAndroid$4.onClick(DialogAndroid.java:252)
        at com.afollestad.materialdialogs.MaterialDialog.onClick(MaterialDialog.java:456)
        at android.view.View.performClick(View.java:6663)
        at android.view.View.performClickInternal(View.java:6635)
        at android.view.View.access$3100(View.java:794)
        at android.view.View$PerformClick.run(View.java:26199)
        at android.os.Handler.handleCallback(Handler.java:907)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:216)
        at android.app.ActivityThread.main(ActivityThread.java:7625)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)

If something can happen multiple times, we should be dispatching events (https://github.com/aakashns/react-native-dialogs/issues/57#issuecomment-350587541), not limiting users by saying they should not use dismissable dialogs.

Also, the problem with the library as it currently is, is that it has a promise-based interface but internally works with callbacks. It would be much cleaner if it worked with promises all the way from JS to native as well.