NoConnectionException: The maximum allowed connection attempts

Hello below is the log I get for my app. What does below error mean and how is this occuring and how to solve this issue?

[log] AMITY_MQTT::Mosquitto client connecting to - ssq.sg.amity.co
[log] asocket::connecting with accessToken eyJhbGciOiJSUzI1NiIsImtpZCI6IkVyd1J6MWtiQ0tQcEQweFpSM0tBN055SEFCSGNFd1NnVEZfajFuY29ZNjQifQ.eyJ1c2VyIjp7InVzZXJJZCI6IjY1Zjg3YzhkOWIyYThlNGY0MGM1ODcwMCIsInB1YmxpY1VzZXJJZCI6IisxMjEzOTk5MzMzMyIsIm5ldHdvcmtJZCI6IjY1ZjczODc4YThhM2IyYjk1Njg3MzQ1MyIsInJlZnJlc2hUb2tlbiI6ImI2MDMxYzhkMDUzNDBlNjFkZDY1YjIyYTliMjdiMGIxYzRjMDI3M2Y0MWI5OGJmNTgxNjViNGM5MzE5ZGI0MmQxOTY0YTgyMDExMjFlMWU3In0sInN1YiI6IjY1Zjg3YzhkOWIyYThlNGY0MGM1ODcwMCIsImlzcyI6Imh0dHBzOi8vYXBpLnVzLmFtaXR5LmNvIiwiaWF0IjoxNzEwNzg5MjE4LCJleHAiOjE3MTMzODEyMTh9.io0CbYEleJ87ScN8hHxCb8WO40AL_L3Ggforij7EfTkVxQO46MIbjpMrlMwxCXQuIzSX9zkK89A-zbzCeA1iSJCCSeG2cIl-O2beEhv1Lg7l_tZ7e_tNqm5y9s0Rox0QHZgzUJFCoDRmey4vYpeiUOTlXJ8tKdGuKx64GtdTEpY4x5taAEvTCU9GlDwle5gDxNZVL_v5wsaIBOn89XlUWrDxuwnZFxgjyVpM6ufjU5AVBk5pwqWdYhot5pRXejAtnvjGhtMTvA0Jp0x9GjmQf5SQGS-Z_oHaN82HI4AC4eQ-9glz1txT2SU7UpALhKUk9fyP4OgOrWxEonEkTtlFVQ
flutter: asocket connect
[log] AMITY_MQTT::OnDisconnected client callback - Client disconnection
[log] AMITY_MQTT::OnDisconnected callback is solicited, this is correct
[log] AMITY_MQTT::client exception - mqtt-client::NoConnectionException: The maximum allowed connection attempts ({3}) were exceeded. The broker is not responding to the connection request message correctly The return code is MqttConnectReturnCode.badUsernameOrPassword

@danielkang98 I will consult with my team and provide you with an update at the earliest convenience.

@danielkang98 Regarding your issue, we need more information, specifically the full code, to allow our team to further investigate the problem you’re encountering.

I see log happening in this amity file when activeClient?.connect is being called (like below).
try { await activeClient?.connect(); } on Exception catch (e) { logger('AMITY_MQTT::client exception - $e'); activeClient?.disconnect(); return MQTT_DISCONNECTED; }

// ignore_for_file: avoid_log, non_constant_identifier_names, prefer_const_declarations, unused_element, unused_field

import 'dart:async';
import 'dart:convert';
import 'dart:developer';

import 'package:amity_sdk/src/core/core.dart';
import 'package:amity_sdk/src/data/data.dart';
import 'package:amity_sdk/src/domain/repo/account_repo.dart';
import 'package:amity_sdk/src/public/amity_core_client.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:mqtt_client/mqtt_client.dart' if (dart.library.html) 'package:mqtt_client/mqtt_browser_client.dart';
import 'package:mqtt_client/mqtt_server_client.dart';

class AmityMQTT {
  MqttServerClient? activeClient;

  static final MQTT_CONNECTED = 0;
  static final MQTT_DISCONNECTED = -1;

  final AccountRepo accountRepo;
  final AmityCoreClientOption amityCoreClientOption;

  StreamSubscription? _accountSubscription;

  AmityMQTT({required this.accountRepo, required this.amityCoreClientOption}) {
    logger('AMITY_MQTT::Mosquitto client init');
  }

  void connect() {
    final currentUser = AmityCoreClient.getCurrentUser();
    _accountSubscription = accountRepo
        .listenAccount(currentUser.userId!)
        .takeWhile((account) => account?.accessToken?.isNotEmpty ?? false)
        .distinct()
        .listen((account) {
      if (account != null) {
        logger('asocket::connecting with accessToken ${account.accessToken}');
        _connect(account);
      }
    });
  }

  Future<int> _connect(AccountHiveEntity accountEntity) async {
    activeClient = MqttServerClient(amityCoreClientOption.mqttEndpoint.endpoint, accountEntity.deviceId!);

    activeClient?.autoReconnect = true;
    // activeClient?.instantiationCorrect = true;
    activeClient?.setProtocolV311();
    activeClient?.keepAlivePeriod = 60;
    activeClient?.port = 443;
    activeClient?.onDisconnected = _onDisconnected;
    activeClient?.onConnected = _onConnected;
    activeClient?.onSubscribed = onSubscribed;
    activeClient?.onUnsubscribed = _onUnsubscribed;
    activeClient?.onSubscribeFail = _onSubscribFailed;

    activeClient?.pongCallback = _pong;
    activeClient?.websocketProtocols = MqttClientConstants.protocolsSingleDefault;
    activeClient?.secure = true;

    /// Create a connection message to use or use the default one. The default one sets the
    /// client identifier, any supplied username/password and clean session,
    /// an example of a specific one below.
    final connMess = MqttConnectMessage()
        .withClientIdentifier(accountEntity.deviceId!)
        .startClean() // Non persistent session for testing
        .withWillQos(MqttQos.atMostOnce)
        .authenticateAs(accountEntity.id!, accountEntity.accessToken!);

    logger('AMITY_MQTT::Mosquitto client connecting to - ${amityCoreClientOption.mqttEndpoint.endpoint}');
    activeClient?.connectionMessage = connMess;

    try {
      await activeClient?.connect();
    } on Exception catch (e) {
      logger('AMITY_MQTT::client exception - $e');
      activeClient?.disconnect();
      return MQTT_DISCONNECTED;
    }

    if (activeClient?.connectionStatus!.state == MqttConnectionState.connected) {
      logger('AMITY_MQTT::Mosquitto client connected ---->  ${activeClient?.clientIdentifier}');
      _subscribeToNetwork();
    } else {
      logger(
          'AMITY_MQTT::ERROR Mosquitto client connection failed - disconnecting, status is ${activeClient?.connectionStatus}');
      activeClient?.disconnect();
      return MQTT_DISCONNECTED;
    }

    //for testing purpose
    // subscribe(
    //     '5b028e4a673f81000fb040e7/social/community/61f2b7289ed52800da3e9c31/post/+');

    return MQTT_CONNECTED;
  }

  void _subscribeToNetwork(){
    final currentUser = AmityCoreClient.getCurrentUser();
      var split = currentUser.path?.split("/");
      String? networkId = split?[0];
      if(networkId!=null){
        subscribe(AmityTopic.NETWORK(networkId));
      }
  }

  void _addClientListeners() {
    final currentUser = AmityCoreClient.getCurrentUser();
    accountRepo
        .listenAccount(currentUser.userId!)
        .takeWhile((account) => account?.isActive == false)
        .distinct()
        .listen((account) {
      _obsoleteClient();
    });
  }

  void _obsoleteClient() {
    activeClient?.disconnect();
    activeClient = null;
  }

  final _completerPool = <String, Completer<bool>>{};
//todo change parameter to AmityTopic
  Future subscribe(AmityTopic topic) async {
    ///Create a completer to add to the pool
    final completer = Completer<bool>();

    if (_completerPool.containsKey(topic.generateTopic())) {
      logger('AMITY_MQTT::Subscribing to - ${topic.generateTopic()} already in progress');
      completer.completeError('Subscription already in progress');
      return completer.future;
    }

    _completerPool[topic.generateTopic()] = completer;

    logger('AMITY_MQTT::Subscribing to - ${topic.generateTopic()}');
    activeClient?.subscribe(topic.generateTopic(), MqttQos.atMostOnce);

    /// Connection timeout for MQTT
    Future.delayed(const Duration(seconds: 30), () {
      if (_completerPool.containsKey(topic)) {
        _completerPool[topic]?.completeError(
            AmityException(message: 'Subcription failed for the topic $topic, Connection timeout', code: 408));
        _completerPool.remove(topic);
      }
    });

    ///Wait for completer to get complete
    return completer.future;
  }

//todo change parameter to AmityTopic
  Future unsubscribe(AmityTopic topic) async {
    ///Create a completer to add to the pool
    final completer = Completer<bool>();

    if (_completerPool.containsKey(topic.generateTopic())) {
      logger('AMITY_MQTT::Unsubscribing to - ${topic.generateTopic()} already in progress');
      completer.completeError('unsubscription already in progress');
      return completer.future;
    }

    _completerPool[topic.generateTopic()] = completer;

    logger('AMITY_MQTT::Unsubscribing to ${topic.generateTopic()}');
    activeClient?.unsubscribe(topic.generateTopic());

    /// Connection timeout for MQTT
    Future.delayed(const Duration(seconds: 30), () {
      if (_completerPool.containsKey(topic)) {
        _completerPool[topic]?.completeError(
            AmityException(message: 'Subcription failed for the topic $topic, Connection timeout', code: 408));
        _completerPool.remove(topic);
      }
    });

    ///Wait for completer to get complete
    return completer.future;
  }

  /// The subscribed callback
  @visibleForTesting
  void onSubscribed(String topic) {
    logger('AMITY_MQTT::Subscription confirmed for topic $topic');
    if (_completerPool.containsKey(topic)) {
      _completerPool[topic]?.complete(true);
      _completerPool.remove(topic);
    }
  }

  /// The subscribed callback
  void _onUnsubscribed(String? topic) {
    logger('AMITY_MQTT::Unsubscription confirmed for topic $topic');
    if (_completerPool.containsKey(topic)) {
      _completerPool[topic]?.complete(true);
      _completerPool.remove(topic);
    }
  }

  void _onSubscribFailed(String topic) {
    logger('AMITY_MQTT::Subscription  Fail for topic $topic');
    if (_completerPool.containsKey(topic)) {
      _completerPool[topic]
          ?.completeError(AmityException(message: 'Subcription failed for the topic $topic', code: 401));
      _completerPool.remove(topic);
    }
  }

  /// The unsolicited disconnect callback
  void _onDisconnected() {
    logger('AMITY_MQTT::OnDisconnected client callback - Client disconnection');
    if (activeClient?.connectionStatus?.disconnectionOrigin == MqttDisconnectionOrigin.solicited) {
      logger('AMITY_MQTT::OnDisconnected callback is solicited, this is correct');
    }
  }

  /// The successful connect callback
  void _onConnected() {
    logger('AMITY_MQTT::OnConnected client callback - Client connection was sucessful');

    activeClient?.updates?.listen((List<MqttReceivedMessage<MqttMessage?>>? c) {
      final recMess = c?[0].payload as MqttPublishMessage;
      final pt = MqttPublishPayload.bytesToStringAsString(recMess.payload.message);

      final payload = MqttPayloadResponse.fromJson(jsonDecode(pt));

      logger(
          'AMITY_MQTT::Notification:: Payload Type - ${payload.eventType} topic is <${c?[0].topic}>, payload is <-- $pt -->');
      //
      final listener = MqttEventListeners().getEvent(payload.eventType);

      if (listener != null && payload.data != null) {
        listener.processEvent(payload.data!);
      }
    });
  }

  /// Pong callback
  void _pong() {
    logger('AMITY_MQTT::Ping response client callback invoked');
  }

  void logger(String logMessage) {
    log(logMessage);
  }
}

and I get exception below

        throw NoConnectionException('The maximum allowed connection attempts '
              '({$maxConnectionAttempts}) were exceeded. '
              'The broker is not responding to the connection request message correctly '
              'The return code is ${connectionStatus.returnCode}');
1 Like

@danielkang98 To assist you better, could you please provide us with the full code snippet where you implement AmityCoreClient.setup and AmityCoreClient.login? This will help us understand your setup and guide you more effectively.

Setting AmityCoreClient.setup in main.dart

Below: main.dart

import 'package:amity_sdk/amity_sdk.dart';
import 'package:app/bindings/root_bindings.dart';
import 'package:app/logger.dart';
import 'package:app/constants/app_theme.dart';
import 'package:app/routes.dart';
import 'package:app/screens/onboarding/welcome_screen.dart';
import 'package:app/screens/root_screen.dart';
import 'package:app/services/notification_service.dart';
import 'package:app/screens/onboarding/onboarding_lock_screen1.dart';
import 'package:app/widgets/lock_screen_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:get/get.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:home_widget/home_widget.dart';
import 'package:upgrader/upgrader.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  try {
    NotificationService().initNotification();
    AppLogger.logInfo("Main Setup FlutterLocalNotificationsPlugin Initialized");
  } catch (exception) {
    AppLogger.logError(
        "Main Setup FlutterLocalNotificationsPlugin error = ${exception.toString()}");
  }
  try {
    await HomeWidget.setAppGroupId('group.imhome.lockscreen');
    await HomeWidget.registerInteractivityCallback(interactiveCallback);

    await HomeWidget.renderFlutterWidget(
      const LockScreenWidget(),
      key: 'lock_screen',
      logicalSize: const Size(200, 200),
    );
    await HomeWidget.renderFlutterWidget(
      const LockScreenWidget(),
      key: 'lock_screen',
      logicalSize: const Size(200, 200),
    );
  } catch (exception) {
    AppLogger.logError("Main Setup HomeWidget error = ${exception.toString()}");
  }
  try {
    await Firebase.initializeApp();
  } catch (exception) {
    AppLogger.logError("Main Setup Firebase error = ${exception.toString()}");
  }
  try {
    // Register an Interactivity Callback. It is necessary that this method is static and public
    // OneSignal.initialize("ffb70490-5aca-462a-9d51-58adf0dfc2cd");
    // OneSignal.Debug.setLogLevel(OSLogLevel.verbose);

    await AmityCoreClient.setup(
      option: AmityCoreClientOption(
        apiKey: 'b0e9be5d39d3f76d1d3fdc1f000a4481d50f84e5b9316a2f',
        httpEndpoint: AmityRegionalHttpEndpoint.US,
      ),
      sycInitialization: true,
    );

    // final imgProvider = AssetImage(screenshot);
    // await precacheImage(imgProvider, context);
  } catch (exception) {
    AppLogger.logError("Main Setup error = ${exception.toString()}");
  }

  AppLogger.logInfo("Main Setup completed");

  runApp(const ImHomeApp());
}

/// Callback invoked by HomeWidget Plugin when performing interactive actions
/// The @pragma('vm:entry-point') Notification is required so that the Plugin can find it
@pragma('vm:entry-point')
Future<void> interactiveCallback(Uri? uri) async {
  // Set AppGroup Id. This is needed for iOS Apps to talk to their WidgetExtensions
  await HomeWidget.setAppGroupId('group.imhome.lockscreen');

  // We check the host of the uri to determine which action should be triggered.
  // if (uri?.host == 'increment') {
  //   await _increment();
  // } else if (uri?.host == 'clear') {
  //   await _clear();
  // }
}

class ImHomeApp extends StatelessWidget {
  const ImHomeApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Portal(
      child: GetMaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'AtHome Moments',
        theme: AppTheme.darkTheme, // Apply the darkTheme from AppTheme
        home: const RootScreen(),
        initialBinding: RootBinding(),
        getPages: routes,
      ),
    );
  }
}

Calling AmityCoreClient.login in RootScreen
userSerive.createUser → AmityCoreClient.login

import 'package:app/services/amity/user_service.dart';
import 'package:app/screens/onboarding/onboarding_lock_screen1.dart';
import 'package:app/widgets/lock_screen_widget.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:app/screens/home/camera_screen.dart';
import 'package:app/screens/legal/privacy_policy_screen.dart';
import 'package:app/screens/onboarding/welcome_screen.dart';
import 'package:app/logger.dart';
import 'package:app/services/hive_service.dart';
import 'package:get/get.dart';
import 'package:home_widget/home_widget.dart';

class RootScreen extends StatefulWidget {
  const RootScreen({Key? key}) : super(key: key);

  @override
  _RootScreenState createState() => _RootScreenState();
}

class _RootScreenState extends State<RootScreen> {
  final UserService userService = Get.find<UserService>();

  @override
  void initState() {
    super.initState();
    HomeWidget.widgetClicked.listen(_launchedFromWidget);
    _renderLockscreenWidget();
    HiveService.init();
  }

  void _launchedFromWidget(Uri? uri) {
    AppLogger.logInfo('CameraScreen: Launched from widget');
  }

  Future<Widget> determineStartScreen() async {
    if (FirebaseAuth.instance.currentUser == null) {
      return const WelcomeScreen();
    }

    try {
      final userData = await userService.fetchUserProfileData();
      if (userData?.username == null) {
        AppLogger.logInfo('RootScreen: User does not have a username');
        return const WelcomeScreen();
      } else {
        // Assuming createUser is an asynchronous operation
        await userService
            .createUser(FirebaseAuth.instance.currentUser!.phoneNumber!);
        AppLogger.logInfo('RootScreen: User logged in successfully');
        return const CameraScreen();
      }
    } catch (exception) {
      AppLogger.logError('RootScreen: Error: $exception');
      return const WelcomeScreen();
    }
  }

  Future<void> _renderLockscreenWidget() async {
    await HomeWidget.renderFlutterWidget(
      const LockScreenWidget(),
      key: 'lock_screen',
      logicalSize: const Size(100, 100),
    );
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Widget>(
      future: determineStartScreen(),
      builder: (BuildContext context, AsyncSnapshot<Widget> snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Scaffold(
              body: Center(child: CircularProgressIndicator()));
        } else if (snapshot.hasError) {
          return Scaffold(
              body: Center(child: Text('Error: ${snapshot.error}')));
        } else {
          return snapshot.data!;
        }
      },
    );
  }
}

userSerive.createUser method below:

  Future<AmityUser> createUser(String userId, {String? dname}) async {
    try {
      AmityUser user;
      if (dname != null) {
        user = await AmityCoreClient.login(userId).displayName(dname).submit();
      } else {
        user = await AmityCoreClient.login(userId).submit();
      }

      userId = userId;
      currentUser = user;

      AppLogger.logInfo("Amity Create User = ${user.toString()}");
      update();
      return user;
    } catch (exception) {
      AppLogger.logError("Create User error = ${exception.toString()}");
      throw Exception("Create User error = ${exception.toString()}");
    }
  }
1 Like

@danielkang98 After reviewing your code, our team has found it to be correct. However, we would like to request additional information for further investigation as follows:

  1. API key
  2. User ID

Please send this information to support.asc@amity.co

UserID: It is happening with all of the users I login with.
+12139991111
+821029930928
etc…

Thank you @danielkang98, our team is investigating this, we will keep you posted.

When will the documentation will be fixed? I am unable to look at the amity Flutter documentation at all.

@amitysupport Any update?

Hello @danielkang98 After checking with the team, it was found that no MQTT endpoint is provided during the SDK setup. Therefore, please also ensure that the endpoints match. For example, if the http endpoint is from the US, the MQTT must be from the US as well.

1 Like