From 89c55ec7c5d6e9f7f8f038c4e6a1b1bbd3024e99 Mon Sep 17 00:00:00 2001 From: Harlan Crystal Date: Sat, 25 Jul 2026 21:30:52 -0700 Subject: [PATCH] Fix inverted staleness guard on the /sync catch-up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FetchAndProcessEventsSinceLastReceivedEvent has a guard meant to skip /sync when the last received event is older than 30 days, past which the server rejects LastSyncAt. It computed the age backwards: var diff = lastEventReceivedAt - _timeService.Now; // past - now => NEGATIVE if (diff.TotalDays > 30) { return; } // therefore never true lastEventReceivedAt is always in the past, so the branch is unreachable and /sync is issued regardless of age. The request then fails server-side, and because the only caller (StreamChatClient.RestoreStateLostDuringDisconnect) invokes it fire-and-forget through LogIfFailed, the exception reaches the logger and nothing else — the client silently gets no replay at all. Corrected to `_timeService.Now - lastEventReceivedAt`. DateTimeOffset subtraction compares UtcDateTime, so a local-offset vs server-offset mismatch is handled correctly. Also removes the dead `currentServerTime` local directly above it. It was never read, and was almost certainly the intended left operand — the tell that this comparison was written wrong and never exercised. Note this only skips a request that was certain to fail; it is not a recovery path. The SDK has no re-hydrate fallback of its own, so bridging a gap this large remains the consumer's job. --- Assets/Plugins/StreamChat/Changelog.txt | 1 + .../Core/LowLevelClient/StreamChatLowLevelClient.cs | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Assets/Plugins/StreamChat/Changelog.txt b/Assets/Plugins/StreamChat/Changelog.txt index 335bd26b..4157fdea 100644 --- a/Assets/Plugins/StreamChat/Changelog.txt +++ b/Assets/Plugins/StreamChat/Changelog.txt @@ -19,6 +19,7 @@ Features: Fixes: +* Fix the 30-day staleness guard on the reconnect /sync catch-up computing its age backwards (lastEventReceivedAt - now, which is negative for any past timestamp), so the guard never fired and /sync was called even with a LastSyncAt the server rejects. Also removes a dead local that was almost certainly the intended operand. * TaskUtils.LogIfFailed now logs connectivity/transport failures as warnings instead of errors/exceptions. The SDK fire-and-forgets its connect, reconnect, and state-restore operations through LogIfFailed; when the device is offline these fail with HttpRequestException / WebException / SocketException / IOException / TimeoutException, which the reconnect flow recovers from - so surfacing them at error severity flooded crash/error reporting (Sentry, Bugsnag, etc.) with handled, non-actionable noise. Genuine (non-connectivity) failures still log as exceptions. Complements the connection-attempt-timeout fix from PR #213. v5.5.0: diff --git a/Assets/Plugins/StreamChat/Core/LowLevelClient/StreamChatLowLevelClient.cs b/Assets/Plugins/StreamChat/Core/LowLevelClient/StreamChatLowLevelClient.cs index b45185e0..7000c00b 100644 --- a/Assets/Plugins/StreamChat/Core/LowLevelClient/StreamChatLowLevelClient.cs +++ b/Assets/Plugins/StreamChat/Core/LowLevelClient/StreamChatLowLevelClient.cs @@ -445,10 +445,10 @@ public async Task FetchAndProcessEventsSinceLastReceivedEvent(IEnumerable 30) { return;