Status Update
Comments
zh...@google.com <zh...@google.com> #2
This is probably happening because there are multiple instances of DataStore active. You should consider managing the DataStore as a singleton. See the attached bug for more info.
ah...@truecaller.com <ah...@truecaller.com> #3
Yes, this is our configuration:
PreferenceDataStoreFactory.create(
scope = CoroutineScope(coroutineContext + SupervisorJob()),
migrations = migrations,
corruptionHandler = ReplaceFileCorruptionHandler(
produceNewData = { emptyPreferences() } // Use an empty preferences in case of file corruption
)
) {
applicationContext.preferencesDataStoreFile(name)
}
zh...@google.com <zh...@google.com> #4
Thanks for the inputs, I'll take a deeper look at it.
ah...@truecaller.com <ah...@truecaller.com> #5
It looks like we found the culprit. It was a third party library that didn't provide a corruption handler. We have two improvement suggestions:
- Make the corruption handler mandatory or provide a default value that recreates an empty file. Otherwise any kind of corruption results in unrecoverable scenario.
- Add data store file name to logs. Otherwise it's impossible to figure out the culprit from the stack trace. It would be helpful to have more details in the stacktrace.
ni...@gmail.com <ni...@gmail.com> #6
ah...@truecaller.com <ah...@truecaller.com> #7
Unfortunately, I cannot share the name of the SDK, but here are a couple of hints to narrow down the problem:
- Add logs around the creation of your data store to make sure it's not your code. Ensure you've implemented corruption handlers.
- Go through recent library updates that you've made.
zh...@google.com <zh...@google.com> #8
Thanks for your inputs, re
Make the corruption handler mandatory or provide a default value that recreates an empty file. Otherwise any kind of corruption results in unrecoverable scenario.
This would be an API change and needs careful reviews. I'll discuss with other owners of this project to see if it's possible.
Add data store file name to logs. Otherwise it's impossible to figure out the culprit from the stack trace. It would be helpful to have more details in the stacktrace.
Right now the place where the exception is thrown has no access to the file name information, I'll try to plumb the info through if there's no API reviews needed.
For the trace stack you provided in #1, is it suppressed in a CorruptionException
or thrown directly?
ah...@gmail.com <ah...@gmail.com> #9
ah...@truecaller.com <ah...@truecaller.com> #10
For the trace stack you provided in #1, is it suppressed in a CorruptionException or thrown directly?
It's suppressed in CorruptionException
.
zh...@google.com <zh...@google.com> #11
Thanks for the contexts in
ah...@truecaller.com <ah...@truecaller.com> #12
Awesome, thank you for taking a look so promptly!
el...@google.com <el...@google.com> #13
Hi there, we have multiple issues open for this same issue, so to consolidate the info on 1 issue tracker, I will be closing this issue "as duplicate".
Description
DataStore Version used: 1.1.1
Android versions: 11 (21%) 12 (16%) 13 (14%) 14 (33%)
Devices: Vivo (22%) Samsung (21%) Oppo (14%) XIaomi (13%) Other (30%)
Error messages:
Protocol message tag had invalid wire type.
Protocol message contained an invalid tag (zero)
Protocol message end-group tag did not match expected tag.
Stacktrace:
androidx.datastore.preferences.protobuf.InvalidProtocolBufferException.<init> (InvalidProtocolBufferException.java:47)
androidx.datastore.preferences.protobuf.InvalidProtocolBufferException.invalidTag (InvalidProtocolBufferException.java:133)
androidx.datastore.preferences.protobuf.CodedInputStream$StreamDecoder.readTag (CodedInputStream.java:2107)
androidx.datastore.preferences.protobuf.CodedInputStreamReader.getFieldNumber (CodedInputStreamReader.java:82)
androidx.datastore.preferences.protobuf.MessageSchema.mergeFromHelper (MessageSchema.java:3913)
androidx.datastore.preferences.protobuf.MessageSchema.mergeFrom (MessageSchema.java:3895)
androidx.datastore.preferences.protobuf.GeneratedMessageLite.parsePartialFrom (GeneratedMessageLite.java:1648)
androidx.datastore.preferences.protobuf.GeneratedMessageLite.parseFrom (GeneratedMessageLite.java:1784)
androidx.datastore.preferences.PreferencesProto$PreferenceMap.parseFrom (PreferencesProto.java:196)
androidx.datastore.preferences.PreferencesMapCompat$Companion.readFrom (PreferencesMapCompat.java:32)
androidx.datastore.preferences.core.PreferencesSerializer.readFrom (PreferencesSerializer.jvm.kt:46)
androidx.datastore.core.okio.OkioReadScope.readData$suspendImpl (OkioStorage.kt:180)
androidx.datastore.core.okio.OkioReadScope.readData (OkioStorage.kt:1)
androidx.datastore.core.StorageConnectionKt$readData$2.invokeSuspend (StorageConnection.kt:74)
androidx.datastore.core.StorageConnectionKt$readData$2.invoke (StorageConnection.kt:20)
androidx.datastore.core.StorageConnectionKt$readData$2.invoke (StorageConnection.kt:20)
androidx.datastore.core.okio.OkioStorageConnection.readScope (OkioStorage.kt:113)
androidx.datastore.core.StorageConnectionKt.readData (StorageConnection.kt:74)
androidx.datastore.core.DataStoreImpl.readDataFromFileOrDefault (DataStoreImpl.kt:331)
androidx.datastore.core.DataStoreImpl.readDataOrHandleCorruption (DataStoreImpl.kt:373)
androidx.datastore.core.DataStoreImpl.access$readDataOrHandleCorruption (DataStoreImpl.kt:53)
androidx.datastore.core.DataStoreImpl$InitDataStore$doRun$initData$1.invokeSuspend (DataStoreImpl.kt:445)
androidx.datastore.core.DataStoreImpl$InitDataStore$doRun$initData$1.invoke (DataStoreImpl.kt:11)
androidx.datastore.core.DataStoreImpl$InitDataStore$doRun$initData$1.invoke (DataStoreImpl.kt:11)
androidx.datastore.core.SingleProcessCoordinator.lock (SingleProcessCoordinator.kt:41)
androidx.datastore.core.DataStoreImpl$InitDataStore.doRun (DataStoreImpl.kt:442)
androidx.datastore.core.RunOnce.runIfNeeded (DataStoreImpl.kt:505)
androidx.datastore.core.DataStoreImpl.readAndInitOrPropagateAndThrowFailure (DataStoreImpl.kt:274)
androidx.datastore.core.DataStoreImpl.handleUpdate (DataStoreImpl.kt:251)
androidx.datastore.core.DataStoreImpl.access$handleUpdate (DataStoreImpl.kt:53)
androidx.datastore.core.DataStoreImpl$writeActor$3.invokeSuspend (DataStoreImpl.kt:215)
androidx.datastore.core.DataStoreImpl$writeActor$3.invoke (DataStoreImpl.kt:13)
androidx.datastore.core.DataStoreImpl$writeActor$3.invoke (DataStoreImpl.kt:13)
androidx.datastore.core.SimpleActor$offer$2.invokeSuspend (SimpleActor.kt:121)
First of all, it's not clear why preferences are corrupted. However, regardless of that, the corruption handler does not seem to kick in. The expected path would be that the preferences are wiped and recreated. That does not seem to happen. If there was in issue during the recreation, we would expect the surpressed stacktrace to appear according to the code here: