You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A failed connectUser() (e.g. device is offline) triggers ChatClient.setUser()'s internal .onErrorSuspend { disconnectSuspend(flushPersistence = true) } handler, which wipes the client's offline Room cache via disconnectUserSuspend(flushPersistence = true) -> repositoryFacade.clear() and resets mutableClientState.clearState(). This happens on every failed connectUser() call, including a plain connectivity failure — not just auth errors — so a cold app launch while offline destroys the exact offline cache that ChatClientConfig(offlineEnabled = true) is meant to preserve for a returning, previously-authenticated user.
This directly contradicts the Offline Support guide, which frames flushPersistence = true as something a caller explicitly opts into (e.g. on logout), not a side effect of a failed reconnect — and the Handling User Connection guide, which explicitly says: "Make sure your implementation handles a missing network without recording it as a fatal error" — implying a connectUser() failure due to missing network is an expected, non-fatal occurrence, yet its side effect (wiping the offline cache) isn't documented anywhere.
SDK version
7.6.0 and 7.7.0 (confirmed on both by reading the actual stream-chat-android-client sources for each version; 7.7.0's changelog doesn't mention a related fix, and re-testing on-device against 7.7.0 reproduces the same behavior)
To Reproduce
Sign in successfully with ChatClient.Builder(apiKey, context).config(ChatClientConfig(offlineEnabled = true)).build(), connectUser(...), and browse channels while online so the offline cache is populated.
Fully close the app (kill the process).
Put the device in airplane mode / disconnect all networks.
Cold-launch the app again and call connectUser(...) for the same user with no timeoutMilliseconds (or any value) — it resolves as Result.Failure since the socket can't connect.
Observe: ChannelsScreen/ChannelListViewModel for this client now has an empty/perpetually-loading channel list, getCurrentUser() returns null, and the client's offline database has been cleared — even though step 1 successfully cached channels for this exact user.
Traced root cause (in io.getstream.chat.android.client.ChatClient, 7.6.0/7.7.0 sources):
privatesuspendfunsetUser(...): Result<ConnectionData> {
...
returnwhen {
...
userState isUserState.NotSet-> {
mutableClientState.setUser(user)
initializeClientWithUser(user, cacheableTokenProvider, isAnonymous)
userStateService.onSetUser(user, isAnonymous)
chatSocket.connectUser(user, isAnonymous)
mutableClientState.setInitializationState(InitializationState.COMPLETE)
waitFirstConnection(timeoutMilliseconds) // <- resolves Result.Failure offline, no timeout given
}
...
}.onErrorSuspend {
disconnectSuspend(flushPersistence =true) // <- runs on ANY Result.Failure, including pure connectivity failure
}
}
privatesuspendfundisconnectUserSuspend(flushPersistence:Boolean) {
...
if (flushPersistence) {
repositoryFacade.clear() // wipes the offline Room cache
userCredentialStorage.clear()
}
...
mutableClientState.clearState() // getCurrentUser() becomes null again...
}
Expected behavior
A connectUser() failure caused purely by lack of connectivity should not flush the offline persistence layer or clear the client's local user state — the whole point of offlineEnabled = true is that a previously-authenticated user can browse cached channels/messages without a live connection. At minimum, this destructive side effect should be documented, or ideally scoped to real auth/credential errors rather than every Result.Failure (including plain network-unreachable cases).
Workaround we're using in the meantime
Checking device connectivity (our own ConnectivityManager-backed monitor) before calling connectUser() at all, and skipping the call entirely when known-offline — this avoids triggering the destructive path, at the cost of not restoring the previously-connected user's session (and thus not showing cached channels) on that specific cold-offline launch.
Additional context
Related: Switching user cause ChannelScreen goes in an infinite loop and no chats are shown #6009 ("Switching user cause ChannelScreen goes in an infinite loop and no chats are shown") describes the same downstream symptom (ChannelsScreen stuck/empty after a disconnect(flushPersistence = true)), triggered by an explicit switchUser() call rather than an implicit connectivity failure — but the underlying "post-flush, channel list never recovers" behavior looks like the same class of issue.
Happy to provide a minimal repro project if useful.
Describe the bug
A failed
connectUser()(e.g. device is offline) triggersChatClient.setUser()'s internal.onErrorSuspend { disconnectSuspend(flushPersistence = true) }handler, which wipes the client's offline Room cache viadisconnectUserSuspend(flushPersistence = true)->repositoryFacade.clear()and resetsmutableClientState.clearState(). This happens on every failedconnectUser()call, including a plain connectivity failure — not just auth errors — so a cold app launch while offline destroys the exact offline cache thatChatClientConfig(offlineEnabled = true)is meant to preserve for a returning, previously-authenticated user.This directly contradicts the Offline Support guide, which frames
flushPersistence = trueas something a caller explicitly opts into (e.g. on logout), not a side effect of a failed reconnect — and the Handling User Connection guide, which explicitly says: "Make sure your implementation handles a missing network without recording it as a fatal error" — implying aconnectUser()failure due to missing network is an expected, non-fatal occurrence, yet its side effect (wiping the offline cache) isn't documented anywhere.SDK version
stream-chat-android-clientsources for each version; 7.7.0's changelog doesn't mention a related fix, and re-testing on-device against 7.7.0 reproduces the same behavior)To Reproduce
ChatClient.Builder(apiKey, context).config(ChatClientConfig(offlineEnabled = true)).build(),connectUser(...), and browse channels while online so the offline cache is populated.connectUser(...)for the same user with notimeoutMilliseconds(or any value) — it resolves asResult.Failuresince the socket can't connect.ChannelsScreen/ChannelListViewModelfor this client now has an empty/perpetually-loading channel list,getCurrentUser()returnsnull, and the client's offline database has been cleared — even though step 1 successfully cached channels for this exact user.Traced root cause (in
io.getstream.chat.android.client.ChatClient, 7.6.0/7.7.0 sources):Expected behavior
A
connectUser()failure caused purely by lack of connectivity should not flush the offline persistence layer or clear the client's local user state — the whole point ofofflineEnabled = trueis that a previously-authenticated user can browse cached channels/messages without a live connection. At minimum, this destructive side effect should be documented, or ideally scoped to real auth/credential errors rather than everyResult.Failure(including plain network-unreachable cases).Workaround we're using in the meantime
Checking device connectivity (our own
ConnectivityManager-backed monitor) before callingconnectUser()at all, and skipping the call entirely when known-offline — this avoids triggering the destructive path, at the cost of not restoring the previously-connected user's session (and thus not showing cached channels) on that specific cold-offline launch.Additional context
ChannelsScreenstuck/empty after adisconnect(flushPersistence = true)), triggered by an explicitswitchUser()call rather than an implicit connectivity failure — but the underlying "post-flush, channel list never recovers" behavior looks like the same class of issue.