Reputation: 1127
I'm using Firestore with the Android SDK (11.6.2) and I'm hitting an exception when my device was offline and reconnects to the Internet.
When requesting a document, firestore fails with the following task exception :
com.google.firebase.firestore.FirebaseFirestoreException: Failed to get document because the client is offline.
However, the device is connected, I can make network requests beside using Firestore and they succeed. This error is not consistent, sometimes the request will succeed right after reconnecting to the Internet. Sometimes, the request fails again and again, then succeeds, sometimes more than one minute after the device has been reconnected to the Internet.
Here is a sample request that produces the exception:
val docRef = firestore.collection("foo").document("bar")
docRef.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d("FirestoreSourceSet", "Get document success")
} else {
Log.e("FirestoreSourceSet", "Get document error", task.exception)
}
}
I'm not using the offline capabilities of Firestore, thus the FirebaseFirestore instance is initialized the first time with the setPersistenceEnabled(false)
flag:
val firestoreSettings = FirebaseFirestoreSettings.Builder()
.setPersistenceEnabled(false)
.build()
val firestore = FirebaseFirestore.getInstance().apply {
this.firestoreSettings = firestoreSettings
}
Why is Firestore returning this error even though the device is online? Am I missing something in the Firestore configuration that would avoid this error?
I tried upgrading Firebase to the 11.8.0 version, but I encounter the same behavior.
These are the logs while trying to fetch sync some data with Firestore (which begins with a document fetch) after leaving airplane mode: https://pastebin.com/xDMG2Pzj
The network is already available before the first Firestore call, as I waited for the Wifi to settle, and check it using the ConnectivityManager of Android before proceeding with Firestore.
The multiple calls are because I manually retry using a button each time I get the error until the document is successfully retrieved.
The first line of the log is when I turn the airplane mode one, which closes the stream of Firestore.
Firebase doesn't have a public tracker, but I reported the issue using their report tool, and made a repo that reproduces the issue.
They acknowledged the issue but could not provide an ETA, so we have to wait:
If we release the fix, we will announce it in our release notes page.
This is still an issue as of firestore-core 17.0.4
Upvotes: 21
Views: 9016
Reputation: 6995
I'm facing the same issue since 2018 and have not yet found a proper solution. It is still happening with version 22.1.2 of the Firestore library for Android. As commented in the source code of DocumentReference
, this exception is thrown when the client is offline and the requested document is not available in the local cache. There is also a recent explanation of this behaviour by Denver Coneybeare.
This exception might occur for DocumentReference.get()
calls. Here's an exemplary stack trace:
com.google.firebase.firestore.FirebaseFirestoreException: Failed to get document because the client is offline.
at com.google.firebase.firestore.DocumentReference.lambda$getViaSnapshotListener$1(DocumentReference.java:331)
at com.google.firebase.firestore.DocumentReference$$Lambda$2.onEvent(DocumentReference.java:8)
at com.google.firebase.firestore.DocumentReference.lambda$addSnapshotListenerInternal$2(DocumentReference.java:504)
at com.google.firebase.firestore.DocumentReference$$Lambda$3.onEvent(DocumentReference.java:16)
at com.google.firebase.firestore.core.AsyncEventListener.lambda$onEvent$0(AsyncEventListener.java:42)
at com.google.firebase.firestore.core.AsyncEventListener$$Lambda$1.run(AsyncEventListener.java:2)
at com.google.firebase.firestore.util.Executors$$Lambda$1.execute(Executors.java)
at com.google.firebase.firestore.core.AsyncEventListener.onEvent(AsyncEventListener.java:39)
at com.google.firebase.firestore.core.QueryListener.raiseInitialEvent(QueryListener.java:176)
at com.google.firebase.firestore.core.QueryListener.onViewSnapshot(QueryListener.java:95)
at com.google.firebase.firestore.core.EventManager.addQueryListener(EventManager.java:97)
at com.google.firebase.firestore.core.FirestoreClient.lambda$listen$6(FirestoreClient.java:160)
at com.google.firebase.firestore.core.FirestoreClient$$Lambda$6.run(FirestoreClient.java:12)
at com.google.firebase.firestore.util.AsyncQueue.lambda$enqueue$2(AsyncQueue.java:436)
at com.google.firebase.firestore.util.AsyncQueue$$Lambda$2.call(AsyncQueue.java:1)
at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor.lambda$executeAndReportResult$1(AsyncQueue.java:322)
at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor$$Lambda$2.run(AsyncQueue.java:1)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
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:229)
at java.lang.Thread.run(Thread.java:919)
I'm sorry if this answer does not solve the problem, but this information would have been too long for a comment on the original post.
Upvotes: 2
Reputation: 23
this may help
Java:
FirebaseFirestore db = FirebaseFirestore.getInstance();
//to reconnect
db.terminate();
db = FirebaseFirestore.getInstance();
Kotlin:
var db = Firebase.firestore
//to reconnect
db.terminate()
db = Firebase.firestore
Upvotes: 0
Reputation: 1
I also have the same problem. There is workaround - application waits some time and makes another attempt to get the data from server.
Here is mockup (this is Flutter/dart):
List<Course> items;
Widget build(BuildContext context) {
...
loadData();
...
//building th UI with data from items list
...
}
loadData() async {
//is not loaded but there is internet connection
if (!isLoaded&&isConnected) {
try {
querySnapshot = await query.getDocuments(source: Source.server);
}
catch (ex) {
print(ex);
Future.delayed(Duration(seconds: 10), () {
// setState to trigger build 10 seconds later to make one more attempt
setState(() {
isLoaded = false;
});
});
return;
}
// here goes the code to handle the result
items = querySnapshot.documents.map((s) => Course.fromDb(s)).toList();
}
Upvotes: 0
Reputation: 1127
This issue was fixed by the release 17.1.5 of Cloud Firestore.
See the official changelog https://firebase.google.com/support/release-notes/android
Cloud Firestore now recovers more quickly from bad network states.
Using my reproduction project with the version 18.0.0, the issue is indeed not present.
Upvotes: 2
Reputation: 138824
From the official documentation:
To use offline persistence, you don't need to make any changes to the code that you use to access Cloud Firestore data. With offline persistence enabled, the Cloud Firestore client library automatically manages online and offline data access and synchronizes local data when the device is back online.
When you initialize Cloud Firestore, you can enable or disable offline persistence. So, when using the following line of code:
val firestoreSettings = FirebaseFirestoreSettings.Builder()
.setPersistenceEnabled(false)
.build()
You actually set the persistence to false
, you are disabling this feature. To solve this, just remove this line of code. Firestore has .setPersistenceEnabled(true)
by default.
Upvotes: 5