razorpay/razorpay-flutter-customui

issue java.lang.IllegalStateException: Reply already submitted

Renatinaveen opened this issue · 14 comments

Facing this issue and app is crashing because of this

java.lang.IllegalStateException: Reply already submitted
	at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:431)
	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:267)
	at com.razorpay.flutter_customui.RazorpayDelegate$1.onPaymentMethodsReceived(RazorpayDelegate.java:114)
	at com.razorpay.BaseRazorpay$6.onResponse(BaseRazorpay.java:1230)
	at com.razorpay.BaseRazorpay$8.run(BaseRazorpay.java:1307)
	at com.razorpay.Q$$U_.onPostExecute(Owl.java:5137)
	at android.os.AsyncTask.finish(AsyncTask.java:771)
	at android.os.AsyncTask.access$900(AsyncTask.java:199)
	at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788)
	at android.os.Handler.dispatchMessage(Handler.java:106)
	at android.os.Looper.loopOnce(Looper.java:201)
	at android.os.Looper.loop(Looper.java:288)
	at android.app.ActivityThread.main(ActivityThread.java:7842)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

@Renatinaveen how were you able to solve this ?

@mishrabhilash i was calling getapps with upi and get subscription amount methods in the init state.

Now I moved the get subscription method inside getapps with upi call issue didn't appear.

java.lang.IllegalStateException:
at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply (Unknown Source:35)
at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success (Unknown Source:14)
at com.razorpay.flutter_customui.RazorpayDelegate.sendReply (Unknown Source:4)
at com.razorpay.flutter_customui.RazorpayDelegate.onPaymentError (Unknown Source:43)
at com.razorpay.flutter_customui.RazorpayDelegate.onLocalActivityResult (Unknown Source:50)
at com.razorpay.flutter_customui.RazorpayDelegate.onActivityResult (Unknown Source:10)

This is happening in a different scenario. We have around 160+ users who are affected in Production

A common cause could be .success getting called more than once. Check your plugin code for such scenarios.

@mishrabhilash I load the UPI apps first and then the payment options like wallet and other users are clicking on the available apps while the payment options are still loading could that be the issue?

I mean calling the Razorpay method again when one call is already happening might be causing this crash?

Razorpay plugins provides the following methods

  1. to get all payment methods.
    getPaymentMethodsRazorPay();

  2. To get all supported UPI Apps
    getAllSupportedUpiApps();

As per our UI, we call both the methods simultaneously.
And this is causing crashes

Fatal Exception: java.lang.IllegalStateException: Reply already submitted
at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:4)
at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:1)
at ki.a$a.a(RazorpayDelegate.java:2)
at com.razorpay.s.a(BaseRazorpay.java:2)
at com.razorpay.u.a(BaseRazorpay.java:4)
at com.razorpay.w0.onPostExecute(Owl.java:3)
at android.os.AsyncTask.finish(AsyncTask.java:695)
at android.os.AsyncTask.access$600(AsyncTask.java:180)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6810)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)

@mrinaljain Unable to reproduce this issue. Can I get a code snippet where you're seeing this happen?

Hi @vivekshindhe
We are calling this two method in our Subscription Screen Init State method

void getRazorPaymentMethod() async {
    paymentMethods = await _razorpayService.getPaymentMethodsRazorPay();
    upiApps=await _razorpayService.getAllSupportedUpiApps();
  }

Crash is happening on random on opening Subscription Screen
We are using paymentMethods value to display wallets list,netbanking list on Checkout Screen
upiApps value to display upi apps UI in Payment CheckOut Screen,

We are calling _razorpay.submit(options) on clicking a particular payment method with respective options object
Example

var options = {
                            "card[cvv]": cardInfoModel?.cvv,
                            "card[expiry_month]": cardInfoModel?.expiryMonth,
                            "card[expiry_year]": cardInfoModel?.expiryYear,
                            "card[name]": cardInfoModel?.cardHolderName,
                            "card[number]": cardInfoModel?.cardNumber,
                            "method": [PaymentMethodRazorPay.card.name](http://paymentmethodrazorpay.card.name/),
                            "email":cardInfoModel?.email,
                            "contact":cardInfoModel?.mobileNumber
                          };

We are calling these method as well for getting logo as well on Checkout Page to show UI

return await razorPay.getBankLogoUrl(netBankingModel.bankKey);
return await razorPay.getWalletLogoUrl(walletModel.walletName);

@imofidul do you have any logs for the crash? Does it happen every run?

Hi @vivekshindhe Log is already share by @mrinaljain .I happens randomly

@imofidul from what I see, the issue is intermittent and you have a service written that wraps Razorpay's functions.
The issue is happening because there's only one methodChannel and there's no complete solution from what I saw in Flutter's issue log.
There are multiple solutions that I can take as a developer. i.e, either have a flag that tells me about the status of the pendingResult or have multiple methodChannels for all functions. But, as mentioned above these aren't complete solutions to this problem. Would it be possible to implement the following for you,

_razorpay.getPaymentMethods().then((value) async => {
          paymentMethods = value,
          upiApps = await _razorpay.getAppsWhichSupportUpi()
   });

This way we reduce the chance of pendingResult clashing when using the same methodCall and by point reduce the intermittent crashes.
While we at Razorpay will look into different solutions.

@vivekshindhe thanks for the update.We will be waiting for permanent solution for this .we are calling like this

 paymentMethods = await _razorpayService.getPaymentMethodsRazorPay();
    upiApps=await _razorpayService.getAllSupportedUpiApps();

But You are suggesting like this

_razorpay.getPaymentMethods().then((value) async => {
          paymentMethods = value,
          upiApps = await _razorpay.getAppsWhichSupportUpi()
   });

I guess technically both are same .Moreover we are passing paymentMethods ,upiApps as routeArgs to someother screen so using your suggested approach would be more error prone.

@imofidul the problem here is while the await part waits, it's not letting flutter clear the pendingResult value that is created in the plugin for the first call which gets reused and hence the error Reply already submitted. My suggestion to use it this way was to give flutter enough time to clear the data from the previous call to go forward with the next one. From the code snippet you shared, I can see that it's setting up to different variables. I'm not sure how you are waiting for these values to be set before routing them, but the same logic can be reused here as well.

Sure will try this