Skip to content

[cloud_firestore] Simple Firestore transaction crashes on physical iOS device (only) #1216

Description

@kroikie

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?

Steps to Reproduce

Firestore.instance.runTransaction((Transaction tx) async {
    DocumentSnapshot docSnapshot = await tx.get(docRef);

      tx.update(
        docRef,
        {
          'title':'A Title'
        },
      );
    }

Logs

> 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!

Activity

  1. kroikie commented on Oct 13, 2019

    @kroikie
    ContributorAuthor

    @guit4eva

    The issue at flutter/flutter#35806 has been closed and moved here. Future collaboration on this issue will be done here.

  2. changed the title [-]Simple Firestore transaction crashes on physical iOS device (only)[/-] [+][cloud_firestore] Simple Firestore transaction crashes on physical iOS device (only)[/+] on Oct 18, 2019
  3. puf commented on Nov 27, 2019

    @puf
    Contributor

    Another report of this in the wild: https://stackoverflow.com/q/59051694

  4. SiyrisSoul commented on Dec 18, 2019

    @SiyrisSoul

    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.

  5. jpainam commented on Feb 22, 2020

    @jpainam

    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) 
  6. forsythe commented on Feb 27, 2020

    @forsythe

    Also getting the above if there are multiple transactions running.

  7. teehtheg commented on Feb 29, 2020

    @teehtheg

    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?

  8. leetworx commented on Mar 1, 2020

    @leetworx

    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.

  9. forsythe commented on Mar 5, 2020

    @forsythe

    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.

  10. pY4x3g commented on Mar 7, 2020

    @pY4x3g

    I wrote a little dirty hack (bd4007a) 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.

  11. added
    impact: crowdAffects many people, though not necessarily a specific customer with an assigned label. (P2)
    on Apr 20, 2020
  12. devibrahimkarahan commented on Jun 10, 2020

    @devibrahimkarahan

    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

  13. Salakar commented on Jul 8, 2020

    @Salakar
    Contributor

    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

  14. locked and limited conversation to collaborators on Aug 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    impact: crowdAffects many people, though not necessarily a specific customer with an assigned label. (P2)plugin: cloud_firestoretype: bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions