LocationOfInterestRepository.getOfflineLoi java.lang.IllegalStateException - LOI not found
Fatal Exception: java.lang.IllegalStateException: LOI not found: uJcwRNB9BB7yPwGhrKF6
at com.google.android.ground.repository.LocationOfInterestRepository.getOfflineLoi(LocationOfInterestRepository.kt:93)
at com.google.android.ground.repository.LocationOfInterestRepository$getOfflineLoi$1.invokeSuspend(:15)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8913)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
Total events by version 0.1.10 (20) 15 for the last 7 days
@shobhitagarwal1612 is this the correct user behaviour?
as per the code
suspend fun getOfflineLoi(surveyId: String, loiId: String): LocationOfInterest {
val survey = localSurveyStore.getSurveyById(surveyId) ?: error("Survey not found: $surveyId")
return localLoiStore.getLocationOfInterest(survey, loiId) ?: error("LOI not found: $loiId")
}
it should crash, but, is it good to crash or should we do something better for the user behaviour?
Are you sure that the application is crashing?
it says Fatal Exception, so I am assuming its an app crash.
And, error("LOI not found: $loiId") throw exception so it should crash.
WDYT?
BTW, the stack trace is from firebase.
From crash logs I found that this is happening in SyncStatusFragment. In this particular usecase, the code isn't wrapped around a try-catch block. So the app must be getting crashed when opening the sync status screen. Can you please try to understand how this is happening and the root cause for the LOIs to be missing?
@anandwana001 is this one still in progress by you?
Part 1 on crashes resolved. Suggestion to check logs to determine the LOI affected and whether they are orphaned from the upload synch. Happening on 9 different surveys
@anandwana001 Hint in logs breadcrumbs in Firebase Crashlytics:
ignoring invalid submission mutation: Unknown jobId YZTumCFHZUNhdIlbwOrK in submission mutation 99
Request to prioritize this before next Field trip @jabramowitz5 FYI
Edge case to test:
- Activate airplane mode
- Collect data in Android app
- Delete related job in web interface (or add some debug code to delete locally)
- Wait for local survey to be updated
- Reenable airplane mode
What happens when the job is deleted before the pending mutations are synced?
LOI 51cJrOKVaRsZFH6isObK in remote survey HZq3OSSYqRIhwsvVWqQH is invalid (Ask Gemini)
com.google.android.ground.persistence.remote.DataStoreException: Missing job dkpfwqijB7UQ0dYEbLzJ
at com.google.android.ground.persistence.remote.DataStoreException$Companion.checkNotNull(DataStoreException.kt:23)
at com.google.android.ground.persistence.remote.firebase.schema.LoiConverter.toLoiUnchecked(LoiConverter.kt:45)
at com.google.android.ground.persistence.remote.firebase.schema.LoiConverter.toLoi-gIAlu-s(LoiConverter.kt:35)
at com.google.android.ground.persistence.remote.firebase.schema.LoiCollectionReference$toLois$2.invokeSuspend(LoiCollectionReference.kt:66)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
2024-11-08 12:54:14.787 10006-10377 LoiCollect...nce$toLois com.google.android.ground W LOI VqAc6Ka5HGUoVmNIIhBd in remote survey HZq3OSSYqRIhwsvVWqQH is invalid (Ask Gemini)
com.google.android.ground.persistence.remote.DataStoreException: Missing job N7FCsKkYswbqR6uT4jq2
at com.google.android.ground.persistence.remote.DataStoreException$Companion.checkNotNull(DataStoreException.kt:23)
at com.google.android.ground.persistence.remote.firebase.schema.LoiConverter.toLoiUnchecked(LoiConverter.kt:45)
at com.google.android.ground.persistence.remote.firebase.schema.LoiConverter.toLoi-gIAlu-s(LoiConverter.kt:35)
at com.google.android.ground.persistence.remote.firebase.schema.LoiCollectionReference$toLois$2.invokeSuspend(LoiCollectionReference.kt:66)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
coming after testing on deleted project after collecting data @shobhitagarwal1612
Reopening to ensure we figure out the root cause to avoid data loss.
I suspect this is also related to the race condition of Survey and LOIs not being loaded before the data collection fragment is rendered.
Suggestion: Wrap the DataCollectionFragment in a container fragment which shows a loading spinner while survey and LOIs are loading.
You should put null skipper on surveyId as survey id is not present in the data store, or you need to refresh data store or add job data in a app cache!
You should put null skipper on surveyId as survey id is not present in the data store, or you need to refresh data store or add job data in a app cache!
- If the user is offline there's no way to refresh the data store.
- The job metadata (not data) is expected to be stored locally before this method is called.
- As mentioned, the core issue is likely that the job metadata isn't loaded from the local store before this flow is triggered.
As you said the job metadata is expected to be stored locally before this method is called,A Server side hook can sync meta data while connection is still active.
As you said the job metadata is expected to be stored locally before this method is called,A Server side hook can sync meta data while connection is still active.
I'm not sure what you mean by "a server side hook" here, but the client already kept up-to-date via Firebase Messaging. Please submit feedback in the form of concrete PRs going forward so that we can better understand your suggestions in context.