I have a simple transaction that updates a Firestore document. It works correctly on Android devices, Android Emulators and iOS emulators, but crashes on a physical iOS device. I have no idea what the error means?
Firestore.instance.runTransaction((Transaction tx) async {
DocumentSnapshot docSnapshot = await tx.get(docRef);
tx.update(
docRef,
{
'title':'A Title'
},
);
}
> Assertion failure in void firebase::firestore::core::Transaction::EnsureCommitNotCalled()(), /Users/path_to_app/ios/Pods/FirebaseFirestore/Firestore/core/src/firebase/firestore/core/transaction.mm:198
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'FIRESTORE INTERNAL ASSERTION FAILED: A transaction object cannot be used after its update callback has been invoked. (expected !committed_)'
**Flutter doctor -v :**
> [✓] Flutter (Channel stable, v1.5.4-hotfix.2, on Mac OS X 10.14.5 18F132, locale en-ZA)
> • Flutter version 1.5.4-hotfix.2 at /Users/me/flutter
> • Framework revision 7a4c33425d (2 months ago), 2019-04-29 11:05:24 -0700
> • Engine revision 52c7a1e849
> • Dart version 2.3.0 (build 2.3.0-dev.0.5 a1668566e5)
>
>
> [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
> • Android SDK at /Users/me/Library/Android/sdk
> • Android NDK location not configured (optional; useful for native profiling support)
> • Platform android-28, build-tools 28.0.3
> • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
> • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)
> • All Android licenses accepted.
>
> [✓] iOS toolchain - develop for iOS devices (Xcode 10.2.1)
> • Xcode at /Applications/Xcode.app/Contents/Developer
> • Xcode 10.2.1, Build version 10E1001
> • ios-deploy 1.9.4
> • CocoaPods version 1.7.1
>
> [✓] Android Studio (version 3.4)
> • Android Studio at /Applications/Android Studio.app/Contents
> • Flutter plugin version 36.1.1
> • Dart plugin version 183.6270
> • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)
>
> [✓] VS Code (version 1.36.0)
> • VS Code at /Applications/Visual Studio Code.app/Contents
> • Flutter extension version 3.2.0
>
> [✓] Connected device (1 available)
> • My iPhone • 7f3fa5e8324c4b79dc44e124318f483d0b63695c • ios • iOS 9.3.5
>
> • No issues found!
@guit4eva
The issue at https://github.com/flutter/flutter/issues/35806 has been closed and moved here. Future collaboration on this issue will be done here.
Another report of this in the wild: https://stackoverflow.com/q/59051694
I'm getting this bug on a physical Android device as well. In my case if I press a button rapidly, causing the transaction to be run simultaneously, it crashes with this error. I'm fairly certain I wasn't experiencing this before with this plugin using mostly the same code a couple months ago.
Getting the same error when the button is pressed rapidly
2020-02-22 21:34:33.651 10497-10606/? E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #3
Process: com.example.mypackage, PID: 10497
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:365)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:257)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:784)
Caused by: java.lang.AssertionError: INTERNAL ASSERTION FAILED: A transaction object cannot be used after its update callback has been invoked.
at com.google.firebase.firestore.u0.b.a(Unknown Source:6)
at com.google.firebase.firestore.u0.b.a(Unknown Source:3)
at com.google.firebase.firestore.p0.q0.c(Unknown Source:9)
at com.google.firebase.firestore.p0.q0.b(Unknown Source:0)
at com.google.firebase.firestore.p0.q0.a(Unknown Source:8)
at com.google.firebase.firestore.l0.a(Unknown Source:52)
at com.google.firebase.firestore.l0.a(Unknown Source:2)
at io.flutter.plugins.firebase.cloudfirestore.a$k.a(Unknown Source:20)
at io.flutter.plugins.firebase.cloudfirestore.a$k.doInBackground(Unknown Source:2)
at android.os.AsyncTask$2.call(AsyncTask.java:345)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:257)Â
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)Â
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)Â
at java.lang.Thread.run(Thread.java:784)Â
Also getting the above if there are multiple transactions running.
I'm experiencing the same problem, with a slightly different cause though.
The issue of transactions happening in parallel I did resolve by buffering/queuing the calls to the transaction function (for example using a BLOC pattern).
But recently I stumbled upon the same problem again. This time, it seems to be caused by the transactions very own retry mechanism. In my case, the retry happens if suddenly connectivity (to the internet) breaks down. In the logs, I observe multiple retries failing with exceptions, which eventually make the app crash with the above exception.
I/flutter (20831): Enter transaction function
E/CloudFirestorePlugin(20831): java.lang.Exception: DoTransaction failed: UNAVAILABLE: Unable to resolve host firestore.googleapis.com
E/CloudFirestorePlugin(20831): java.util.concurrent.ExecutionException: java.lang.Exception: DoTransaction failed: UNAVAILABLE: Unable to resolve host firestore.googleapis.com
E/CloudFirestorePlugin(20831): at com.google.android.gms.tasks.Tasks.zzb(Unknown Source:61)
E/CloudFirestorePlugin(20831): at com.google.android.gms.tasks.Tasks.await(Unknown Source:33)
E/CloudFirestorePlugin(20831): at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$4.apply(CloudFirestorePlugin.java:527)
E/CloudFirestorePlugin(20831): at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$4.apply(CloudFirestorePlugin.java:479)
E/CloudFirestorePlugin(20831): at com.google.firebase.firestore.FirebaseFirestore.lambda$runTransaction$0(com.google.firebase:firebase-firestore@@21.3.0:301)
E/CloudFirestorePlugin(20831): at com.google.firebase.firestore.FirebaseFirestore$$Lambda$5.call(Unknown Source:6)
E/CloudFirestorePlugin(20831): at com.google.android.gms.tasks.zzv.run(Unknown Source:2)
E/CloudFirestorePlugin(20831): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
E/CloudFirestorePlugin(20831): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
E/CloudFirestorePlugin(20831): at java.lang.Thread.run(Thread.java:764)
E/CloudFirestorePlugin(20831): Caused by: java.lang.Exception: DoTransaction failed: UNAVAILABLE: Unable to resolve host firestore.googleapis.com
E/CloudFirestorePlugin(20831): at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$4$1$1.error(CloudFirestorePlugin.java:509)
E/CloudFirestorePlugin(20831): at io.flutter.plugin.common.MethodChannel$IncomingResultHandler.reply(MethodChannel.java:210)
E/CloudFirestorePlugin(20831): at io.flutter.embedding.engine.dart.DartMessenger.handlePlatformMessageResponse(DartMessenger.java:111)
E/CloudFirestorePlugin(20831): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessageResponse(FlutterJNI.java:652)
E/CloudFirestorePlugin(20831): at android.os.MessageQueue.nativePollOnce(Native Method)
E/CloudFirestorePlugin(20831): at android.os.MessageQueue.next(MessageQueue.java:325)
E/CloudFirestorePlugin(20831): at android.os.Looper.loop(Looper.java:142)
E/CloudFirestorePlugin(20831): at android.app.ActivityThread.main(ActivityThread.java:6541)
E/CloudFirestorePlugin(20831): at java.lang.reflect.Method.invoke(Native Method)
E/CloudFirestorePlugin(20831): at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
E/CloudFirestorePlugin(20831): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
I/flutter (20831): Enter transaction function
E/CloudFirestorePlugin(20831): java.lang.Exception: DoTransaction failed: UNAVAILABLE: Unable to resolve host firestore.googleapis.com
E/CloudFirestorePlugin(20831): java.util.concurrent.ExecutionException: java.lang.Exception: DoTransaction failed: UNAVAILABLE: Unable to resolve host firestore.googleapis.com
E/CloudFirestorePlugin(20831): at com.google.android.gms.tasks.Tasks.zzb(Unknown Source:61)
E/CloudFirestorePlugin(20831): at com.google.android.gms.tasks.Tasks.await(Unknown Source:28)
E/CloudFirestorePlugin(20831): at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$4.apply(CloudFirestorePlugin.java:527)
E/CloudFirestorePlugin(20831): at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$4.apply(CloudFirestorePlugin.java:479)
E/CloudFirestorePlugin(20831): at com.google.firebase.firestore.FirebaseFirestore.lambda$runTransaction$0(com.google.firebase:firebase-firestore@@21.3.0:301)
E/CloudFirestorePlugin(20831): at com.google.firebase.firestore.FirebaseFirestore$$Lambda$5.call(Unknown Source:6)
E/CloudFirestorePlugin(20831): at com.google.android.gms.tasks.zzv.run(Unknown Source:2)
E/CloudFirestorePlugin(20831): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
E/CloudFirestorePlugin(20831): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
E/CloudFirestorePlugin(20831): at java.lang.Thread.run(Thread.java:764)
E/CloudFirestorePlugin(20831): Caused by: java.lang.Exception: DoTransaction failed: UNAVAILABLE: Unable to resolve host firestore.googleapis.com
E/CloudFirestorePlugin(20831): at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$4$1$1.error(CloudFirestorePlugin.java:509)
E/CloudFirestorePlugin(20831): at io.flutter.plugin.common.MethodChannel$IncomingResultHandler.reply(MethodChannel.java:210)
E/CloudFirestorePlugin(20831): at io.flutter.embedding.engine.dart.DartMessenger.handlePlatformMessageResponse(DartMessenger.java:111)
E/CloudFirestorePlugin(20831): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessageResponse(FlutterJNI.java:652)
E/CloudFirestorePlugin(20831): at android.os.MessageQueue.nativePollOnce(Native Method)
E/CloudFirestorePlugin(20831): at android.os.MessageQueue.next(MessageQueue.java:325)
E/CloudFirestorePlugin(20831): at android.os.Looper.loop(Looper.java:142)
E/CloudFirestorePlugin(20831): at android.app.ActivityThread.main(ActivityThread.java:6541)
E/CloudFirestorePlugin(20831): at java.lang.reflect.Method.invoke(Native Method)
E/CloudFirestorePlugin(20831): at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
E/CloudFirestorePlugin(20831): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
E/AndroidRuntime(20831): FATAL EXCEPTION: AsyncTask #1
E/AndroidRuntime(20831): Process: com.teeh.missioncontrol_flutter, PID: 20831
E/AndroidRuntime(20831): java.lang.RuntimeException: An error occurred while executing doInBackground()
E/AndroidRuntime(20831): at android.os.AsyncTask$3.done(AsyncTask.java:353)
E/AndroidRuntime(20831): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
E/AndroidRuntime(20831): at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
E/AndroidRuntime(20831): at java.util.concurrent.FutureTask.run(FutureTask.java:271)
E/AndroidRuntime(20831): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
E/AndroidRuntime(20831): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
E/AndroidRuntime(20831): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
E/AndroidRuntime(20831): at java.lang.Thread.run(Thread.java:764)
E/AndroidRuntime(20831): Caused by: java.lang.AssertionError: INTERNAL ASSERTION FAILED: A transaction object cannot be used after its update callback has been invoked.
E/AndroidRuntime(20831): at com.google.firebase.firestore.util.Assert.fail(com.google.firebase:firebase-firestore@@21.3.0:46)
E/AndroidRuntime(20831): at com.google.firebase.firestore.util.Assert.hardAssert(com.google.firebase:firebase-firestore@@21.3.0:31)
E/AndroidRuntime(20831): at com.google.firebase.firestore.core.Transaction.ensureCommitNotCalled(com.google.firebase:firebase-firestore@@21.3.0:246)
E/AndroidRuntime(20831): at com.google.firebase.firestore.core.Transaction.lookup(com.google.firebase:firebase-firestore@@21.3.0:81)
E/AndroidRuntime(20831): at com.google.firebase.firestore.Transaction.getAsync(com.google.firebase:firebase-firestore@@21.3.0:191)
E/AndroidRuntime(20831): at com.google.firebase.firestore.Transaction.get(com.google.firebase:firebase-firestore@@21.3.0:228)
E/AndroidRuntime(20831): at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$5.doInBackground(CloudFirestorePlugin.java:569)
E/AndroidRuntime(20831): at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$5.doInBackground(CloudFirestorePlugin.java:564)
E/AndroidRuntime(20831): at android.os.AsyncTask$2.call(AsyncTask.java:333)
E/AndroidRuntime(20831): at java.util.concurrent.FutureTask.run(FutureTask.java:266)
E/AndroidRuntime(20831): ... 4 more
Does anybody have an idea on how to deal with that?
In my experience, this seems to more often than not be associated with loss/change of connectivity (especially under poor/spotty coverage - e.g. in process of handing over from WIFI to LTE...)
I've managed to reduce the overall impact of this issue by ensuring that I check for connectivity before trying to execute any firestore transactions, but there are still occasions where this fails.
The most frustrating thing about this from what I can see is that these errors do not appear to get trapped/propagated through catchError - on either tx.update or runTransaction... on those occasions where an app hits this issue it is a hard crash. Every time.
In a similar situation with @leetworx as wrapping the transactions in a catch block does nothing at all. This is especially frustrating for developing multiplayer apps where simultaneous user actions causes one to crash.
I wrote a little dirty hack (bd4007a28b27fc5838d2849dae6ba875a8b635e2) to solve the crashes at least on android, the problem is that an AssertionError is thrown and only Exceptions are catched (not Error's), I changed the two catch clauses to Throwables and the app does not crash anymore. But we need a better solution for this but currently I don't have time to understand the full code. I think there is something going wrong with concurrent threads but the error is also thrown if using two devices and firing only once for each device.
to use my dirty hack put this in your pubspec.yaml (not recommendend):
cloud_firestore:
git:
url: https://github.com/pY4x3g/flutterfire.git
ref: bd4007a28b27fc5838d2849dae6ba875a8b635e2
path: packages/cloud_firestore/cloud_firestore
Edit: I think I found the root cause of the problem. If the data (on the firebase servers) is changed between get and update there will be an additional get with the same transaction id of the get and update operation before which is not allowed and should not happen. There is nothing I can do on the java code to solve the issue, the problem has to be in the dart code. But unfortunately I'm not able to recompile the dart code for a package (I'm kind of new to dart and flutter). So the hack above should work for android and should not cause any issues but maybe someone is able to find the issue in the dart code with my provided insights.
Same crash on real Android device [Samsung Grand Prime Os: 5.1.1]
Reproduce: When I trying to run transaction code blocks (get and update) simultaneously on two different device (the other device is android emulator) on one collection.
Note: The code block work successfully but still crash.
Thx @pY4x3g, it works
Hey all, as part of our on-going work for #2582, this has been resolved in our Firebase Firestore rework (#2913) - which has now been merged into master. We'll look at publishing some prereleases in the next few days. Thank you
Most helpful comment
I'm getting this bug on a physical Android device as well. In my case if I press a button rapidly, causing the transaction to be run simultaneously, it crashes with this error. I'm fairly certain I wasn't experiencing this before with this plugin using mostly the same code a couple months ago.