fix(chat): guard cancelStream and _replaceMessageInAll against disposed Ref #87
Add ref.mounted checks across async gaps in cancelStream, _abortStreamImmediately, and upfront in _replaceMessageInAll and _clearPendingApproval to prevent 'Cannot use the Ref of NotifierProvider... after it has been disposed' crash when stopping a response. Fixes #87.
abdulmominsakib committed
Sep 21, 2026 at 09:28 UTC
adf140fe24fe9be0406b348f8709c0d663eed23f
1 file changed
+11
-1
lib/features/chat/providers/chat_notifier.dart
+11
-1
@@ -294,7 +294,9 @@ class ChatNotifier extends Notifier<ChatState> {
294
if (!pending.completer.isCompleted) {
295
pending.completer.complete(false);
296
}
297
- state = state.copyWith(clearPendingApproval: true);
297
+ if (ref.mounted) {
298
+ state = state.copyWith(clearPendingApproval: true);
299
+ }
300
}
301
}
302
@@ -536,6 +538,8 @@ class ChatNotifier extends Notifier<ChatState> {
538
_uiUpdateTimer = null;
539
_clearPendingApproval();
540
541
+ if (!ref.mounted) return;
542
+
543
ref.read(chatServiceProvider)?.cancelStream();
544
ref.read(chatBackgroundServiceProvider).stop();
545
ref.read(isStreamingProvider.notifier).setStreaming(false);
@@ -1821,6 +1825,8 @@ class ChatNotifier extends Notifier<ChatState> {
1825
_uiUpdateTimer?.cancel();
1826
_uiUpdateTimer = null;
1827
_clearPendingApproval();
1828
+ if (!ref.mounted) return;
1829
+
1830
ref.read(chatServiceProvider)?.cancelStream();
1831
ref.read(chatBackgroundServiceProvider).stop();
1832
@@ -1830,6 +1836,7 @@ class ChatNotifier extends Notifier<ChatState> {
1836
_lastSavedReasoningLength = 0;
1837
1838
await _saveService?.flush();
1839
+ if (!ref.mounted) return;
1840
1841
final streamingMessage = _latestStreamingMessage ?? state.streamingMessage;
1842
if (streamingMessage != null) {
@@ -1841,9 +1848,11 @@ class ChatNotifier extends Notifier<ChatState> {
1848
stopReason: 'cancelled',
1849
);
1850
await _saveMessage(finalMessage);
1851
+ if (!ref.mounted) return;
1852
_replaceMessageInState(finalMessage, clearStreaming: true);
1853
}
1854
1855
+ if (!ref.mounted) return;
1856
state = state.copyWith(isStreaming: false, clearStreaming: true);
1857
ref.read(isStreamingProvider.notifier).setStreaming(false);
1858
_latestStreamingMessage = null;
@@ -2475,6 +2484,7 @@ class ChatNotifier extends Notifier<ChatState> {
2484
}
2485
2486
void _replaceMessageInAll(Message message, {bool clearStreaming = false}) {
2487
+ if (!ref.mounted) return;
2488
final updatedAll = state.allMessages.map((m) {
2489
return m.id == message.id ? message : m;
2490
}).toList();