@tduncan / Cortana / commits / c7e5a83

fix: refactor ActiveServerNotifier to use ref.listen and update model selection logic to prevent Riverpod assertion errors

abdulmominsakib committed Apr 20, 2026 at 14:37 UTC c7e5a83e9b5df1d815faff4bfb7fd298daca17b4
2 files changed +37 -17
lib/features/chat/providers/chat_providers.dart
+6 -5
@@ -47,7 +47,9 @@ final autoSelectFirstLoadedModelProvider = FutureProvider<void>((ref) async {
47 final status = ref.watch(connectionStatusProvider);
48
49 if (activeServer == null) {
50 - Future.microtask(() => ref.read(selectedModelProvider.notifier).clear());
50 + // Use await Future.value() to defer outside the current build frame.
51 + await Future.value();
52 + ref.read(selectedModelProvider.notifier).clear();
53 return;
54 }
55
@@ -58,7 +60,8 @@ final autoSelectFirstLoadedModelProvider = FutureProvider<void>((ref) async {
60
61 // If a model is selected but belongs to a different server, clear it
62 if (selectedModel != null && selectedModel.serverId != activeServer.id) {
61 - Future.microtask(() => ref.read(selectedModelProvider.notifier).clear());
63 + await Future.value();
64 + ref.read(selectedModelProvider.notifier).clear();
65 // Continue to try auto-selecting for the new server
66 } else if (selectedModel != null) {
67 // Already have a valid model selected for this server
@@ -94,9 +97,7 @@ final autoSelectFirstLoadedModelProvider = FutureProvider<void>((ref) async {
97 .firstOrNull;
98
99 if (firstLoadedModel != null) {
97 - Future.microtask(() {
98 - ref.read(selectedModelProvider.notifier).setModel(firstLoadedModel);
99 - });
100 + ref.read(selectedModelProvider.notifier).setModel(firstLoadedModel);
101 }
102 } catch (e) {
103 // Silently fail auto-selection
lib/features/servers/providers/server_providers.dart
+31 -12
@@ -239,25 +239,43 @@ class ServersNotifier extends AsyncNotifier<List<Server>> {
239 class ActiveServerNotifier extends Notifier<Server?> {
240 @override
241 Server? build() {
242 - final serversAsync = ref.watch(serversProvider);
242 + // Use ref.listen instead of ref.watch to avoid triggering invalidateSelf
243 + // during a rebuild cycle, which causes a Riverpod assertion error on
244 + // pausedActiveSubscriptionCount.
245 + ref.listen<AsyncValue<List<Server>>>(serversProvider, (prev, next) {
246 + if (next.hasValue) {
247 + Future.microtask(() => _updateFromServers(next.value!));
248 + }
249 + });
250 +
251 + final prefs = ref.read(sharedPreferencesProvider);
252 + final serversAsync = ref.read(serversProvider);
253 final servers = serversAsync.value ?? [];
244 - if (servers.isEmpty) return null;
254 + return _resolveServer(servers, prefs.getString('defaultServerId'));
255 + }
256
246 - final prefs = ref.watch(sharedPreferencesProvider);
247 - final defaultServerId = prefs.getString('defaultServerId');
257 + Server? _resolveServer(List<Server> servers, String? defaultServerId) {
258 + if (servers.isEmpty) return null;
259
260 if (defaultServerId != null && defaultServerId.isNotEmpty) {
250 - final matchingServer = servers.where((s) => s.id == defaultServerId);
251 - if (matchingServer.isNotEmpty) {
252 - return matchingServer.first;
253 - }
261 + final matching = servers.where((s) => s.id == defaultServerId);
262 + if (matching.isNotEmpty) return matching.first;
263 }
264
256 - if (servers.isNotEmpty) {
257 - final defaultServer = servers.where((s) => s.isDefault);
258 - return defaultServer.isNotEmpty ? defaultServer.first : servers.first;
265 + final defaults = servers.where((s) => s.isDefault);
266 + return defaults.isNotEmpty ? defaults.first : servers.first;
267 + }
268 +
269 + void _updateFromServers(List<Server> servers) {
270 + final prefs = ref.read(sharedPreferencesProvider);
271 + final currentId = state?.id;
272 + final resolved = _resolveServer(
273 + servers,
274 + currentId ?? prefs.getString('defaultServerId'),
275 + );
276 + if (resolved?.id != state?.id) {
277 + state = resolved;
278 }
260 - return null;
279 }
280
281 void setActiveServer(Server? server) {
@@ -271,6 +289,7 @@ class ActiveServerNotifier extends Notifier<Server?> {
289 }
290 }
291
292 +
293 class ConnectionStatusNotifier extends Notifier<ConnectionStatus> {
294 @override
295 ConnectionStatus build() {