From ce8d76a6ade159562667ba6962ac847c4cf0ffbf Mon Sep 17 00:00:00 2001 From: Ice Cerberus <214443964+ice-cerberus@users.noreply.github.com> Date: Wed, 14 Jan 2026 16:05:05 +0200 Subject: [PATCH] fix: handles error when loading followers in profile --- .../relays/relay_auth_provider.r.dart | 15 ++++++++++++ .../user/providers/count_provider.r.dart | 15 ++++++++---- .../providers/followers_count_provider.r.dart | 24 +++++++++++-------- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/lib/app/features/ion_connect/providers/relays/relay_auth_provider.r.dart b/lib/app/features/ion_connect/providers/relays/relay_auth_provider.r.dart index 7dcca3ba0f..479bc766fd 100644 --- a/lib/app/features/ion_connect/providers/relays/relay_auth_provider.r.dart +++ b/lib/app/features/ion_connect/providers/relays/relay_auth_provider.r.dart @@ -59,6 +59,12 @@ class RelayAuth extends _$RelayAuth { ref.read(relaysReplicaDelayProvider.notifier).setDelay(); return true; } + // If relay is already authenticated with a different public key (user switch/logout race condition), + // close the relay connection. RelayClosedMixin will automatically invalidate the relay provider, + // causing the next request to get a fresh connection with correct credentials. + if (RelayAuthService.isAlreadyAuthenticatedWithDifferentKeyError(error)) { + relay.close(); + } return false; }, ); @@ -188,4 +194,13 @@ class RelayAuthService { static bool isRelayAuthoritativeError(Object? error) { return error is SendEventException && error.code.startsWith('relay-is-authoritative'); } + + /// Detects if the error indicates the relay is already authenticated with a different public key. + /// This can happen during user switch/logout when a relay connection is reused before being invalidated. + static bool isAlreadyAuthenticatedWithDifferentKeyError(Object? error) { + if (error is! SendEventException) return false; + final errorMessage = error.code.toLowerCase(); + return errorMessage.contains('already authenticated') && + errorMessage.contains('different public key'); + } } diff --git a/lib/app/features/user/providers/count_provider.r.dart b/lib/app/features/user/providers/count_provider.r.dart index 11f4896b2b..9663544153 100644 --- a/lib/app/features/user/providers/count_provider.r.dart +++ b/lib/app/features/user/providers/count_provider.r.dart @@ -110,11 +110,16 @@ class Count extends _$Count { }, ); - await ref.read(ionConnectNotifierProvider.notifier).sendEvent( - requestEvent, - actionSource: ActionSourceRelayUrl(relay.keys.first.url), - cache: false, - ); + try { + await ref.read(ionConnectNotifierProvider.notifier).sendEvent( + requestEvent, + actionSource: ActionSourceRelayUrl(relay.keys.first.url), + cache: false, + ); + } catch (sendError) { + relay.keys.first.unsubscribe(subscription.id); + rethrow; + } final responseEntity = await messagesFuture; diff --git a/lib/app/features/user/providers/followers_count_provider.r.dart b/lib/app/features/user/providers/followers_count_provider.r.dart index fc8eb75304..5807a1f5bc 100644 --- a/lib/app/features/user/providers/followers_count_provider.r.dart +++ b/lib/app/features/user/providers/followers_count_provider.r.dart @@ -28,16 +28,20 @@ class FollowersCount extends _$FollowersCount { ), ]; - return await ref.watch( - countProvider( - actionSource: ActionSourceUser(pubkey), - requestData: EventCountRequestData(filters: filters), - key: pubkey, - type: EventCountResultType.followers, - cache: cache, - network: network, - ).future, - ) as FutureOr; + try { + return await ref.watch( + countProvider( + actionSource: ActionSourceUser(pubkey), + requestData: EventCountRequestData(filters: filters), + key: pubkey, + type: EventCountResultType.followers, + cache: cache, + network: network, + ).future, + ) as FutureOr; + } catch (error) { + return null; + } } void addOne() {