GetStream / stream-chat-flutter

Flutter Chat SDK - Build your own chat app experience using Dart, Flutter and the Stream Chat Messaging API.
https://getstream.io/chat/sdk/flutter/
Other
881 stars 316 forks source link

StreamChatNetworkError(code: 1000, message: Unauthorised, token not defined) after rebuild of StreamChat widget #1841

Open flodaniel opened 5 months ago

flodaniel commented 5 months ago

Which packages are you using?

stream_chat_flutter, stream_chat_persistance, stream_chat_localizations

On what platforms did you experience the issue?

iOS, Android

What version are you using?

stream_chat_flutter: 8.0.0-beta.2 stream_chat_localizations: 8.0.0-beta.2 stream_chat_persistence: 8.0.0-beta.2

What happened?

I have the below code to manage updates to my client (e.g. user logs out and logs in with a different account). If stream emits for the same user again it seems to create a new instance as i then get StreamChatNetworkError(code: 1000, message: Unauthorised, token not defined) when calling .watch on a channel:

return StreamBuilder(
      stream: StreamChatService.clientStream,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return StreamChat(
            backgroundKeepAlive: const Duration(seconds: 5),
            client: snapshot.data!,
            streamChatThemeData: CustomStreamChatTheme.initTheme(context),
            child: child,
          );
        }

        return child ?? const SizedBox();
      },
    );

Steps to reproduce

1. Connect user and create channel
2. Rebuild the widget 
3. Fail to watch another new channel. At at the same time when then trying to open the chat view it crashes on this line:
` final userId = StreamChat.of(context).currentUser!.id;` with `_TypeError (Null check operator used on a null value)`

Supporting info to reproduce

No response

Relevant log output

No response

Flutter analyze output

No response

Flutter doctor output

[✓] Flutter (Channel stable, 3.16.9, on macOS 14.1.2 23B92 darwin-arm64, locale en-AT)
    • Flutter version 3.16.9 on channel stable at /Users/floriandaniel/Documents/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 41456452f2 (7 days ago), 2024-01-25 10:06:23 -0800
    • Engine revision f40e976bed
    • Dart version 3.2.6
    • DevTools version 2.28.5

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/floriandaniel/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = /Users/floriandaniel/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15C500b
    • CocoaPods version 1.12.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2023.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)

[✓] IntelliJ IDEA Community Edition (version 2023.2.2)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.85.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.80.0

Code of Conduct

esarbanis commented 5 months ago

Hi @flodaniel , why do you use the client itself and not client.currentUserStream?

flodaniel commented 5 months ago

The stream here is a custom stream in my app, that I used to resolve issues when a user logged out and a new user logged in. When that happens I create a new StreamChatClient and this stream emits the new client.

flodaniel commented 4 months ago

I can reproduce a crash on final userId = StreamChat.of(context).currentUser!.id; in the message_list_view after a disconnect and reconnet with a new user when using the belwo code. Other operations like queryChannels work as expected with the new user.

To disconnect:

  Future<void> logout() async {
    try {
      await _tokenRefreshListener?.cancel();
      await _badgeListener?.cancel();
      final token = await _getDeviceToken();
      if (token != null) {
        try {
          await client.removeDevice(token);
        } catch (_) {}
      }
      await client.disconnectUser(flushChatPersistence: true);
    } catch (error, stackTrace) {
      unawaited(SentryService().recordError(error, stackTrace: stackTrace));
    } finally {
      _initialized = null;
    }
  }

To connect:


  Future<OwnUser> _connectUser() async {
    final paveUser = _userRepository.user;
    final streamUsername =
        StreamChatHelper.convertUsernameToStreamUsername(paveUser.username);
    final streamChatUser = User(
      id: streamUsername,
      name: paveUser.displayName,
      image: paveUser.username,
    );
    final tokens = await _authenticationRepository.tokens();
    final streamChatToken = tokens.streamChatToken;
    return await client.connectUser(
      streamChatUser,
      streamChatToken,
    );
  }

Worth to note that the StreamChat widget is not destroyed when the user logs out and logs in again.

Edit: I fixed it by moving the StreamChat widget further down the tree where it gets destroyed if the user logs out. Not sure if this is still considered a bug then?

esarbanis commented 4 months ago

Thank you for the clarification @flodaniel , I have yet another question, do you use a different apiKey for each user? If not I don't see why you have to recreate the StreamChatClient each time. A connectUser and a disconnectUser should work fine. By keeping the same StreamChatClient instance you can expose its currentUserStream rather than itself.

flodaniel commented 4 months ago

We don't. We started recreating it due to issues with the unread messages count.