Skip to content

Firebase firestore crashing on batch update during offline mode #3510

@DhiyaneshwaranR

Description

@DhiyaneshwaranR
  • Android Studio Arctic Fox | 2020.3.1 Patch 4
    Build #AI-203.7717.56.2031.7935034, built on November 21, 2021
    Runtime version: 11.0.10+0-b96-7249189 aarch64
    VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
    macOS 12.2.1
    GC: G1 Young Generation, G1 Old Generation
    Memory: 2048M
    Cores: 8

  • Firebase Component: Firestore

  • Component version: 10.0.1

[REQUIRED] Step 3: Describe the problem

Writing a batch commit during offline mode and then turning the network online causes internal firestore crash

Steps to reproduce:

  1. Ensure your app is in offline mode
  2. Write to firestore using batch write when in offline mode
  3. Close relevant app in emulator
  4. Open app while online [ connected to internet/network]
  5. App crases upon start

Attached Logs :

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.buyhappysalesapp, PID: 18768
java.lang.RuntimeException: Internal error in Cloud Firestore (24.0.1).
at com.google.firebase.firestore.util.AsyncQueue.lambda$panic$3(AsyncQueue.java:539)
at com.google.firebase.firestore.util.AsyncQueue$$ExternalSyntheticLambda3.run(Unknown Source:2)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'com.google.firebase.firestore.model.DocumentKey com.google.firebase.firestore.model.MutableDocument.getKey()' on a null object reference
at com.google.firebase.firestore.model.mutation.MutationBatch.applyToLocalView(MutationBatch.java:117)
at com.google.firebase.firestore.local.LocalDocumentsView.recalculateAndSaveOverlays(LocalDocumentsView.java:164)
at com.google.firebase.firestore.local.LocalDocumentsView.recalculateAndSaveOverlays(LocalDocumentsView.java:195)
at com.google.firebase.firestore.local.LocalStore.lambda$acknowledgeBatch$3$com-google-firebase-firestore-local-LocalStore(LocalStore.java:310)
at com.google.firebase.firestore.local.LocalStore$$ExternalSyntheticLambda17.get(Unknown Source:4)
at com.google.firebase.firestore.local.SQLitePersistence.runTransaction(SQLitePersistence.java:228)
at com.google.firebase.firestore.local.LocalStore.acknowledgeBatch(LocalStore.java:301)
at com.google.firebase.firestore.core.SyncEngine.handleSuccessfulWrite(SyncEngine.java:440)
at com.google.firebase.firestore.core.MemoryComponentProvider$RemoteStoreCallback.handleSuccessfulWrite(MemoryComponentProvider.java:109)
at com.google.firebase.firestore.remote.RemoteStore.handleWriteStreamMutationResults(RemoteStore.java:666)
at com.google.firebase.firestore.remote.RemoteStore.access$500(RemoteStore.java:53)
at com.google.firebase.firestore.remote.RemoteStore$2.onWriteResponse(RemoteStore.java:201)
at com.google.firebase.firestore.remote.WriteStream.onNext(WriteStream.java:185)
at com.google.firebase.firestore.remote.WriteStream.onNext(WriteStream.java:49)
at com.google.firebase.firestore.remote.AbstractStream$StreamObserver.lambda$onNext$1$com-google-firebase-firestore-remote-AbstractStream$StreamObserver(AbstractStream.java:119)
at com.google.firebase.firestore.remote.AbstractStream$StreamObserver$$ExternalSyntheticLambda3.run(Unknown Source:4)
at com.google.firebase.firestore.remote.AbstractStream$CloseGuardedRunner.run(AbstractStream.java:67)
at com.google.firebase.firestore.remote.AbstractStream$StreamObserver.onNext(AbstractStream.java:110)
at com.google.firebase.firestore.remote.FirestoreChannel$1.onMessage(FirestoreChannel.java:131)
at io.grpc.internal.DelayedClientCall$DelayedListener.onMessage(DelayedClientCall.java:447)
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInternal(ClientCallImpl.java:656)
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInContext(ClientCallImpl.java:641)
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor$DelayedStartFactory.run(AsyncQueue.java:234)
at java.lang.Thread.run(Thread.java:764)

Code where the error occcurs :

         class CheckOutActivity(
            val performanceActivity: PerformanceActivity,
             performanceId : String
          ) : Request() {

    private val performanceActivityDocumentReference =
        Firebase.firestore.collection(DatabaseConstants.PERFORMANCE)
            .document(performanceId)
            .collection(DatabaseConstants.PERFORMANCE_ACTIVITY)
            .document(performanceActivity.documentId.toString())

    private val performanceDocumentReference =
        Firebase.firestore.collection(DatabaseConstants.PERFORMANCE)
            .document(performanceId)


    override suspend fun execute() {

        val timeInMillis = Calendar.getInstance().timeInMillis
        val timeDifference = timeInMillis - performanceActivity.checkedInTime!!

        performanceActivityDocumentReference
            .update(
                mapOf(
                "checkedOutTime" to timeInMillis,
                "active" to false,
                "timeSpent" to timeDifference
                )
            ).addOnSuccessListener {
                performanceActivityDocumentReference.get().addOnSuccessListener {
                    val activity = it.toObject<PerformanceActivity>()
                    when(timeDifference/1000){
                        in 0..10 -> performanceDocumentReference.update("timings.tenSeconds",FieldValue.increment(1))
                        in 10..20 -> performanceDocumentReference.update("timings.twentySeconds",FieldValue.increment(1))
                        in 20..30 -> performanceDocumentReference.update("timings.thirtySeconds",FieldValue.increment(1))
                        in 30..40 -> performanceDocumentReference.update("timings.fortySeconds",FieldValue.increment(1))
                        in 40..50 -> performanceDocumentReference.update("timings.fiftySeconds",FieldValue.increment(1))
                        in 50..60 -> performanceDocumentReference.update("timings.oneMinute",FieldValue.increment(1))
                        else -> performanceDocumentReference.update("timings.oneMinuteGreater",FieldValue.increment(1))
                    }

                    var updateMap = mapOf(
                        "calls.visitedCall" to FieldValue.increment(1),
                        "calls.notVisitedCall" to FieldValue.increment(-1),
                    )
                    if(activity?.orderTaken==true && activity?.order!=null){
                        updateMap = updateMap.plus("calls.productiveCall" to FieldValue.increment(1))
                        updateMap = updateMap.plus("salesTotal" to FieldValue.increment(activity?.order.totalAmount!!))

                    }
                    performanceDocumentReference.update(updateMap)
                        .addOnSuccessListener {
                            store.dispatch(
                                PerformanceRequests.UpdateActivePerformance(false)
                            )
                        }

                }
            }
    }

    data class Reset(val performanceActivity: PerformanceActivity? = null) : Action
}

// TODO(you): code here to reproduce the problem
// Error occurs when patchUpdate of below code has document as null object as mentioned in logs.

                    var updateMap = mapOf(
                        "calls.visitedCall" to FieldValue.increment(1),
                        "calls.notVisitedCall" to FieldValue.increment(-1),
                    )
                    if(activity?.orderTaken==true && activity?.order!=null){
                        updateMap = updateMap.plus("calls.productiveCall" to FieldValue.increment(1))
                        updateMap = updateMap.plus("salesTotal" to FieldValue.increment(activity?.order.totalAmount!!))

                    }
                    performanceDocumentReference.update(updateMap)
                        .addOnSuccessListener {
                            store.dispatch(
                                PerformanceRequests.UpdateActivePerformance(false)
                            )
                        }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions