Solvedflutterfire [cloud_firestore] INTERNAL ASSERTION FAILED: A transaction object cannot be used after its update callback has been invoked.

Describe the bug
App crash when adding new data. It doesn't print any error in flutter developement. But if you open android log it show:

java.lang.RuntimeException: An error occurred while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:318) at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354) at java.util.concurrent.FutureTask.setException(FutureTask.java:223) at java.util.concurrent.FutureTask.run(FutureTask.java:242) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) at java.lang.Thread.run(Thread.java:761) 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.util.Assert.fail(com.google.firebase:firebase-firestore@@21.3.0:46) at com.google.firebase.firestore.util.Assert.hardAssert(com.google.firebase:firebase-firestore@@21.3.0:31) at com.google.firebase.firestore.core.Transaction.ensureCommitNotCalled(com.google.firebase:firebase-firestore@@21.3.0:246) at com.google.firebase.firestore.core.Transaction.lookup(com.google.firebase:firebase-firestore@@21.3.0:81) at com.google.firebase.firestore.Transaction.getAsync(com.google.firebase:firebase-firestore@@21.3.0:191) at com.google.firebase.firestore.Transaction.get(com.google.firebase:firebase-firestore@@21.3.0:228) at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$5.doInBackground(CloudFirestorePlugin.java:569) at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$5.doInBackground(CloudFirestorePlugin.java:564) at android.os.AsyncTask$2.call(AsyncTask.java:304) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)  at java.lang.Thread.run(Thread.java:761) 

To Reproduce
Steps to reproduce the behavior:
This is so occasional.

  1. Add new data.
  2. Get data

Expected behavior
App should not crash

54 Answers

✔️Accepted Answer

Tracked this down to Firebase offline use and Transactions.

This will happen when you are using either BATCHWRITES or runTransaction in ANDROID and you have no INTERNET connection/limited Internet connection/or unstable internet connection at the point of where the transaction runs.

So to reproduce, run your code that uses either a runTransaction (Ensure that internet is not on). By default, TX require ONLINE access and should FAIL immediately where you can catch the exception. For iOS an exception is raised. For Android - no exception is raised and the transaction trys to run regardless.

No wait a while (5-10 secs) , then turn on INTERNET - after about 10 or so seconds when connection re-establishes itself, FLUTTER crashes.

I dont get this happening in iOS. I recall this working some time back so expect this to be a configuration/regression issue with cloud_firestore and potentially other plugins.

This is my setup :

cloud_firestore: 0.13.4
firebase_auth: 0.15.4

and : 

dependency_overrides:
  firebase_core: 0.4.4

Build gradle (Snapshot)

 dependencies {
        classpath 'com.android.tools.build:gradle:3.5.0' 3.5.3  
        classpath 'com.google.gms:google-services:4.3.3'   
         
        classpath 'com.google.firebase:firebase-crashlytics-gradle:2.0.0-beta02'  
    }

and my build.gradle in Android/app :

dependencies {
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
    implementation 'com.google.firebase:firebase-analytics:17.2.2'  
  
    implementation 'com.google.firebase:firebase-crashlytics:17.0.0-beta01'   
}

This is CRITICAL. I cannot release to the PLAYSTORE with this issue.

Other Answers:

Same issue here. This actually happens with both iOS and Android. Live devices and Simulators.

Note as per #1969 (comment)

  1. You must encapsulate your runTransaction with an await
  2. Issue is related to the Transaction timing out and the internal assertion being raised rather than a PlatformException being thrown which we can trap.

Remember - transactions should :

A. Fail when in OFFLINE mode
B. If the TX is repeated 5 times and doesnt complete
C. If it times out

This issue now occurs on both iOS and Android and the assertion now takes precedence on A-C which is where the bug is.

What does work :

  • As a short term FIX - Increase the timeout on your transaction. This helps where long/complex transactions require more than 5 seconds to run.

What always fails :

Run your TX code code on your device/simulator with NO INTERNET - internally, your TX will be repeated 5 times, then turn on your internet. Your TX will fail and you will get the assertion error.

Note - to simulate the issue above, you need to have (say) a routine that inserts/delete lots of documents (try 20,30,50 etc) within a Single TX.

3 Months on and no Fix ???

THIS IS A HUGE ISSUE FLUTTER/FIREBASE TEAM - A REGRESSION ISSUE AS THIS USED TO WORK FLAWLESSLY.

Seems to same here. iOS is good. Only android appear.

2020-02-11 15:19:18.335 13830-14111/? E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #6
    Process: live.effy.app.dev, PID: 13830
    java.lang.RuntimeException: An error occurred while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:354)
        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:245)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)
     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.util.Assert.fail(com.google.firebase:firebase-firestore@@21.3.0:46)
        at com.google.firebase.firestore.util.Assert.hardAssert(com.google.firebase:firebase-firestore@@21.3.0:31)
        at com.google.firebase.firestore.core.Transaction.ensureCommitNotCalled(com.google.firebase:firebase-firestore@@21.3.0:246)
        at com.google.firebase.firestore.core.Transaction.lookup(com.google.firebase:firebase-firestore@@21.3.0:81)
        at com.google.firebase.firestore.Transaction.getAsync(com.google.firebase:firebase-firestore@@21.3.0:191)
        at com.google.firebase.firestore.Transaction.get(com.google.firebase:firebase-firestore@@21.3.0:228)
        at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$5.doInBackground(CloudFirestorePlugin.java:569)
        at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$5.doInBackground(CloudFirestorePlugin.java:564)
        at android.os.AsyncTask$2.call(AsyncTask.java:333)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at java.lang.Thread.run(Thread.java:764) 

This happens to me when running multiple transactions.

@Ehesp Firstly - can you shed some light on what was asked by @alexda12 a few days back please - I'm certain this information is critical in developers deciding whether to park development with Flutter/Firebase or to persevere and attempt to roll with the current pain points of this severe regression issue.

Secondly , as per your message stating as a workaround :

I'd say for now, try and stick with WriteBatches & FieldValue support until the stable/tested update lands

Adopting Firebase batches aka batch Writes will not help the majority of transaction based code since READS will be paramount especially when dealing with complicated queries, collection groups and transactions that span multiple documents and collections.

This issue has actually be around since late Aug 2019. From my analysis - It originally surfaced in Cloud Firestore 0.13.0+1.

0.13.4 actually fixed the crashing in Android in Offline mode but then there was another regression issue with Firebase_core and 0.4.4 was meant to fix this issue along with another regression issue with Firebase_auth 0.15.4. Unfortunately - the whole Firebase API eco system is a mess with respect to versioning and dependencies. Generally , a developer might take the approach to always upgrade to the latest version of the FlutterFire SDK's but in my experience, I've found this counterproductive - and my advice to any Flutter developer reading this thread is to stay put with what you have. If your app works and you dont have any bugs in any of the standard Flutter/Firebase API's and you dont have a compelling reason to upgrade , then stay put. Its not worth the headache and regression issues that you will inevitably experience. I have not updated to Flutter 1.17.2. I am still on 1.12.13 hotfix 5. It works, I am soon to release my app (have been waiting 8 months for this TX issue to be resolved and then I can release) and I really don't have the time to go through the pain again of upgrading Flutter (1.78 to 1.9x was a major headache) - So will either upgrade Flutter after I go live or potentially go back to Xamarin which I didn't want to do (and investigate Xamarin MAUI).

Regarding this TX issue - everyone might want to try and go back to 0.12.10+2 or 0.12. Currently I am having some success with this version.

More Issues: