agentsclimarketplace

Cometchat flutter v6 troubleshooting

Skill cometchat/cometchat-skills/skills/cometchat-flutter-v6-troubleshooting

Add CometChat chat & messaging and voice & video calls to any React, Next.js, React Native, Angular, Android, iOS, or Flutter project through your AI coding agent. Works with Claude Code, Cursor, Codex, VS Code Copilot, Windsurf, Cline, Kiro, and 50+ more agents.

Install
npx -y skills add cometchat/cometchat-skills --skill cometchat-flutter-v6-troubleshooting

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.

What its author says it does

Copied from the file, not written here

Diagnose and fix CometChat Flutter UIKit v6 integration problems. Covers init failures, login errors, UI rendering issues, keyboard problems, call failures, listener leaks, theme jank, and platform-specific build errors. Use when seeing errors, crashes, or unexpected behavior with CometChat components.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

36.6 KB, as published. Nobody here has run it

Ground truth: cometchat_chat_uikit: ^6.0 — pub-cache source + ui-kit/flutter. Official docs: https://www.cometchat.com/docs/ui-kit/flutter/overview · Docs MCP: claude mcp add --transport http cometchat-docs https://www.cometchat.com/docs/mcp (or fetch the URL directly without MCP). Verify symbols against the installed package/source before relying on them.

CometChat Flutter UIKit v6 — Troubleshooting Guide

Comprehensive guide for diagnosing and fixing CometChat Flutter UIKit v6 integration problems.


1. Quick Diagnosis Flow

Use this decision tree to jump to the right section:

What's happening?
│
├─ App crashes or errors on startup
│  └─ Go to → Section 2: Init & Login Errors
│
├─ UI looks wrong, layout broken, keyboard issues
│  └─ Go to → Section 3: UI Rendering Issues
│
├─ Calls not working, call screen blank or stuck
│  ├─ Outgoing screen NEVER renders (peer rings, caller shows nothing) → Section 4.7 (V6 navigatorKey trap)
│  ├─ Stuck on "Calling…" after peer accepts → Section 4.8 (upgrade to 6.0.1)
│  └─ Otherwise → Section 4: Call Issues
│
├─ Events not firing, duplicate events, memory leaks
│  └─ Go to → Section 5: Listener Issues
│
├─ Build fails on Android or iOS
│  └─ Go to → Section 6: Build Errors
│
├─ App is slow, janky scrolling, laggy keyboard
│  └─ Go to → Section 7: Performance Issues
│
└─ Platform-specific weirdness (Android/iOS/Web)
   └─ Go to → Section 8: Platform-Specific Issues

2. Init & Login Errors

2.1 "Authentication null"

  • Symptom: Error message Authentication null or Please log in to CometChat before calling this method when using any CometChat component or SDK call.
  • Cause: CometChatUIKit.init() was not called, or was called but not awaited before using components or calling login.
  • Fix: Ensure init() completes before any other CometChat usage:
// ✅ CORRECT — await init before anything else
final settings = (UIKitSettingsBuilder()
      ..appId = 'APP_ID'
      ..region = 'us'
      ..authKey = 'AUTH_KEY'
      ..subscriptionType = CometChatSubscriptionType.allUsers)
    .build();

await CometChatUIKit.init(
  uiKitSettings: settings,
  onSuccess: (_) => debugPrint('Init done'),
  onError: (e) => debugPrint('Init failed: ${e.message}'),
);

// ❌ WRONG — login before init completes (race condition)
CometChatUIKit.init(uiKitSettings: settings);
CometChatUIKit.login('uid');

2.2 "APP ID null"

  • Symptom: Error APP ID null or appId is required during init.
  • Cause: appId not set in UIKitSettingsBuilder.
  • Fix: Set appId before calling .build():
final settings = (UIKitSettingsBuilder()
      ..appId = 'YOUR_APP_ID'  // ← Must be set
      ..region = 'us'
      ..authKey = 'YOUR_AUTH_KEY')
    .build();

2.3 ERR_ALREADY_LOGGED_IN

  • Symptom: Error ERR_ALREADY_LOGGED_IN when calling CometChatUIKit.login().
  • Cause: Calling login when a session already exists. After init(), the SDK restores cached sessions automatically.
  • Fix: Check CometChatUIKit.loggedInUser after init before calling login:
CometChatUIKit.init(
  uiKitSettings: settings,
  onSuccess: (_) {
    if (CometChatUIKit.loggedInUser != null) {
      // Already logged in — skip login, go to home
      navigateToHome();
    } else {
      // No session — show login screen
      navigateToLogin();
    }
  },
);

2.4 "Android internal error" on login

  • Symptom: Login fails with a vague Android internal error message.
  • Cause: Multiple possible causes — incorrect auth key, UID doesn't exist in CometChat dashboard, beta SDK bug, or network issue.
  • Fix:
    1. Verify credentials are correct in the CometChat dashboard
    2. Verify the UID exists in the dashboard
    3. Try calling CometChat.login(uid, authKey) directly to isolate UIKit vs SDK issue
    4. If using beta SDK, try the stable release
    5. Check network connectivity and firewall rules

2.5 Guard screen stuck on spinner

  • Symptom: App shows a loading spinner forever after init. The auth guard never resolves.
  • Cause: Using the callback-based CometChat.getLoggedInUser() after init instead of the synchronous CometChatUIKit.loggedInUser. The callback API silently fails when no session exists — neither onSuccess nor onError fires.
  • Fix: Use the synchronous check after init:
// ✅ CORRECT — synchronous check, always resolves
CometChatUIKit.init(
  uiKitSettings: settings,
  onSuccess: (_) {
    final hasUser = CometChatUIKit.loggedInUser != null;
    setState(() {
      _loggedIn = hasUser;
      _initializing = false;
    });
  },
);

// ❌ WRONG — callback may never fire when no session exists
CometChatUIKit.init(
  uiKitSettings: settings,
  onSuccess: (_) {
    CometChat.getLoggedInUser(
      onSuccess: (user) { /* may never fire */ },
      onError: (e) { /* may never fire */ },
    );
  },
);

// ❌ ALSO WRONG — redundant native bridge round-trip
CometChatUIKit.init(
  uiKitSettings: settings,
  onSuccess: (_) async {
    final user = await CometChatUIKit.getLoggedInUser(); // Unnecessary!
  },
);

2.6 Region error (ERR_INVALID_REGION)

  • Symptom: Init fails with ERR_INVALID_REGION.
  • Cause: Region string is uppercase or not one of the valid values.
  • Fix: Use lowercase region string — valid values are 'us', 'eu', 'in':
// ✅ CORRECT
..region = 'us'

// ❌ WRONG
..region = 'US'
..region = 'United States'

2.7 StateError from uninitialized ServiceLocator

  • Symptom: StateError: not initialized when creating a BLoC manually.
  • Cause: Component's ServiceLocator.instance.setup() was not called before creating the BLoC. UIKit widgets do this automatically, but manual BLoC creation requires it.
  • Fix: Call setup before creating the BLoC:
// ✅ CORRECT
ConversationsServiceLocator.instance.setup();
final bloc = ConversationsBloc(
  getLoggedInUserUseCase: ConversationsServiceLocator.instance.getLoggedInUserUseCase,
);

// ❌ WRONG — setup not called
final bloc = ConversationsBloc(
  getLoggedInUserUseCase: ConversationsServiceLocator.instance.getLoggedInUserUseCase,
);

3. UI Rendering Issues

3.1 Double keyboard compensation (layout jumps) — PRE-6.0.1 symptom

  • Symptom: When the keyboard opens, the message list jumps or there's extra white space. Content shifts twice — once from Flutter's Scaffold resize, once from the composer's internal keyboard handling.
  • Cause: A pre-6.0.1 kit. Before kit fix ENG-34434, the composer did not clamp its keyboard spacing to Flutter's viewInsets, so a Scaffold with resizeToAvoidBottomInset: true (the default) double-compensated. On ^6.0.1 the composer clamps to viewInsets, so true is correct and does NOT double-compensate.
  • Fix: Upgrade cometchat_chat_uikit to ^6.0.1 and keep resizeToAvoidBottomInset: true (or omit it — true is the default). Setting false is only a stopgap on old kits you can't upgrade.
// ✅ CORRECT on ^6.0.1 — true (or omit; true is the default). Composer clamps
//   to viewInsets (ENG-34434), so no double-compensation.
Scaffold(
  resizeToAvoidBottomInset: true,
  body: Column(
    children: [
      Expanded(child: CometChatMessageList(user: user)),
      CometChatMessageComposer(user: user),
    ],
  ),
)

// ⚠ PRE-6.0.1 STOPGAP ONLY — false suppresses the double gap on kits that
//   predate the ENG-34434 clamp. Prefer upgrading the kit.
Scaffold(
  resizeToAvoidBottomInset: false,
  body: Column(
    children: [
      Expanded(child: CometChatMessageList(user: user)),
      CometChatMessageComposer(user: user),
    ],
  ),
)

This applies everywhere the composer is used: messages screen, thread screen, or any custom screen.

3.2 Stale user/group data

  • Symptom: User name, avatar, or group info doesn't update in real-time. Old data persists even after changes.
  • Cause: Passing widget.user or widget.group directly to UIKit components instead of maintaining mutable state that updates from listeners.
  • Fix: Keep mutable _user/_group in your State class and update from SDK listeners:
class _MessagesScreenState extends State<MessagesScreen> {
  late User? _user;
  late Group? _group;

  @override
  void initState() {
    super.initState();
    _user = widget.user;
    _group = widget.group;
    // Register listeners to update _user/_group on changes
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: true, // ^6.0.1: composer clamps to viewInsets (ENG-34434)
      body: Column(
        children: [
          Expanded(child: CometChatMessageList(user: _user, group: _group)),
          CometChatMessageComposer(user: _user, group: _group),
        ],
      ),
    );
  }
}

3.3 No typing indicators / presence events

  • Symptom: Online/offline status never updates. Typing indicators don't appear. No presence events fire. No error is thrown.
  • Cause: subscriptionType was not set in UIKitSettingsBuilder. Omitting it silently disables all presence events.
  • Fix: Always set subscriptionType:
// ✅ CORRECT
UIKitSettingsBuilder()
  ..appId = 'APP_ID'
  ..region = 'us'
  ..authKey = 'AUTH_KEY'
  ..subscriptionType = CometChatSubscriptionType.allUsers

// ❌ WRONG — no error, but presence events never fire
UIKitSettingsBuilder()
  ..appId = 'APP_ID'
  ..region = 'us'
  ..authKey = 'AUTH_KEY'
  // subscriptionType missing!

3.4 Messages not updating in real-time

  • Symptom: New messages don't appear until the screen is refreshed or re-opened.
  • Cause: Multiple possible causes:
    1. SDK message listener not registered (BLoC handles this automatically — check component is mounted)
    2. subscriptionType not set (see 3.3)
    3. Component was disposed and listener removed
  • Fix:
    1. Ensure subscriptionType is set in UIKitSettings
    2. Verify the CometChatMessageList widget is mounted and not disposed
    3. If using custom BLoC, ensure it registers CometChat.addMessageListener() in its constructor and removes it in close()

3.5 Theme jank during keyboard animation

  • Symptom: Visible jank (stuttering, dropped frames) when the keyboard opens or closes, especially on message screens.
  • Cause: Theme values (CometChatThemeHelper.getColorPalette(context), etc.) are being looked up inside build(). During keyboard animation, MediaQuery changes trigger rebuilds, and each lookup does expensive InheritedWidget traversal (44–95ms instead of <16ms).
  • Fix: Cache theme values in didChangeDependencies() with a _themeInitialized flag:
// ✅ CORRECT — cache once, reuse on every build
class _MyWidgetState extends State<MyWidget> {
  late CometChatColorPalette _colorPalette;
  late CometChatSpacing _spacing;
  late CometChatTypography _typography;
  bool _themeInitialized = false;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    if (!_themeInitialized) {
      _colorPalette = CometChatThemeHelper.getColorPalette(context);
      _spacing = CometChatThemeHelper.getSpacing(context);
      _typography = CometChatThemeHelper.getTypography(context);
      _themeInitialized = true;
    }
  }

  @override
  Widget build(BuildContext context) {
    // Use _colorPalette, _spacing, _typography — no lookups here
    return Container(color: _colorPalette.primary);
  }
}

// ❌ WRONG — lookup in build causes jank during keyboard animation
@override
Widget build(BuildContext context) {
  final colors = CometChatThemeHelper.getColorPalette(context); // Expensive!
  return Container(color: colors.primary);
}

3.6 Extra white space between composer and keyboard

  • Symptom: Visible gap between the message composer and the keyboard when it opens.
  • Cause: Safe area bottom padding being applied when the keyboard is open. The keyboard already covers the safe area, so adding safe area padding on top creates extra space.
  • Fix: Cache MediaQuery.paddingOf(context).bottom once in didChangeDependencies(). Never wrap the composer in an extra SafeArea widget — CometChatMessageComposer already handles bottom inset internally via SliverSpacing:
// ✅ CORRECT — cache safe area once, no extra SafeArea wrapper
class _MessagesScreenState extends State<MessagesScreen> {
  double _bottomSafeArea = 0;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _bottomSafeArea = MediaQuery.paddingOf(context).bottom;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: true, // ^6.0.1: composer clamps to viewInsets (ENG-34434)
      body: Column(
        children: [
          Expanded(child: CometChatMessageList(user: widget.user)),
          CometChatMessageComposer(user: widget.user), // No SafeArea wrapper!
        ],
      ),
    );
  }
}

// ❌ WRONG — SafeArea wrapper adds bottom padding the composer already handles
Scaffold(
  resizeToAvoidBottomInset: true,
  body: Column(
    children: [
      Expanded(child: CometChatMessageList(user: widget.user)),
      SafeArea(  // ← Causes extra white gap when keyboard opens
        child: CometChatMessageComposer(user: widget.user),
      ),
    ],
  ),
)

4. Call Issues

4.1 "auth token null" on call init

  • Symptom: Calls SDK fails with auth token null or similar authentication error when trying to start a call.
  • Cause: The Calls SDK was initialized before the Chat SDK completed init and login. The Calls SDK needs the auth token from a successful chat login (rule CALLS_INIT_AFTER_CHAT_INIT — see cometchat-flutter-v6-calls §1.0).
  • Fix: When ..enableCalls = true is set on UIKitSettingsBuilder, CallEventService handles both CometChatUIKitCalls.init() and CometChatUIKitCalls.loginWithAuthToken() internally — chat init must complete first. For manual integrations, gate calls init on chat init success:
// ✅ CORRECT — chat init first, calls init in onSuccess
await CometChatUIKit.init(
  uiKitSettings: settings,
  onSuccess: (_) async {
    // For manual calls integration (no ..enableCalls = true):
    // CometChatUIKitCalls.init takes raw appId + region STRINGS (not a settings
    // builder) and reports via callbacks — verified vs cometchat_uikit_calls.dart:9.
    CometChatUIKitCalls.init(
      'APP_ID',
      'us',
      onSuccess: (_) {},
      onError: (e) => debugPrint('Calls init failed: $e'),
    );
  },
  onError: (e) => debugPrint('Chat init failed: ${e.message}'),
);

// ❌ WRONG — calls init runs before chat init completes
CometChatUIKit.init(uiKitSettings: settings);          // not awaited
await CometChatUIKitCalls.init(callAppSettings);       // auth token null

4.2 "session already started"

  • Symptom: Error session already started when trying to join or start a call.
  • Cause: Two distinct causes — diagnose both:
    1. Duplicate CometChatUIKitCalls.init() within one app lifecycle. The Calls SDK is single-init (rule CALL_INIT_ONCE — see cometchat-flutter-v6-calls). Calling init more than once (e.g., from multiple bootstrap paths, hot-restart with stale state) emits this error.
    2. Stale call session from a prior call that was not ended cleanly — user navigated away without hanging up, or the app was killed mid-call.
  • Fix:
// ✅ CAUSE (a) — single-init guard at app boot
bool _callsInitDone = false;
Future<void> initCallsOnce(CallAppSettings settings) async {
  if (_callsInitDone) return;
  await CometChatUIKitCalls.init(settings);
  _callsInitDone = true;
}

// ✅ CAUSE (b) — clean up the stale session via the UIKit-namespaced API.
// The method is endSession (NOT endCall) and takes named callbacks, no sessionId
// — verified vs cometchat_uikit_calls.dart:236.
await CometChatUIKitCalls.endSession(
  onSuccess: (_) {},
  onError: (e) => debugPrint('endSession failed: $e'),
);

// ❌ WRONG — bare CometChat.endCall is the Chat SDK API, not the calls cleanup
CometChat.endCall(sessionId, onSuccess: ..., onError: ...);

4.3 "CallManager not found" / "Calling module not found"

  • Symptom: Android native error CallManager not found or CometChat Calling module not found.
  • Cause: The CometChat Calling native module is not properly linked on Android. This can happen with ProGuard stripping, missing dependencies, or build configuration issues.
  • Fix:
    1. Ensure ProGuard keep rules are in place (see Section 6.1)
    2. Verify cometchat_chat_uikit is properly added to pubspec.yaml
    3. Run flutter clean and rebuild
    4. Check that android.enableJetifier=true is in gradle.properties

4.4 "startSession null" on Android

  • Symptom: startSession returns null on Android with no error feedback. The call screen may appear blank or stuck.
  • Cause: Known Android SDK issue where startSession silently fails. A 5-second timeout workaround exists but provides no error feedback.
  • Fix: This is a known SDK-level issue. Workarounds:
    1. Implement a timeout wrapper around startSession calls
    2. Show a retry option to the user if the call screen doesn't load within 5 seconds
    3. Check for updates to cometchat_calls_sdk that may fix this

4.5 Incoming call not received

  • Symptom: Incoming calls are not shown to the receiver. The caller sees the outgoing call screen but the receiver gets nothing.
  • Cause: Multiple possible causes:
    1. subscriptionType not set (presence/events disabled)
    2. Push notification / VoIP setup incomplete
    3. Call listeners not registered
    4. App is in background without proper background handling
  • Fix:
    1. Ensure subscriptionType is set to CometChatSubscriptionType.allUsers
    2. Verify FCM/APNs push notification setup for background calls
    3. Check that call event listeners are registered
    4. For cross-platform issues (Android↔iOS↔React), verify all platforms are on compatible SDK versions

4.6 Calls SDK not re-initialized after logout

  • Symptom: After logout and re-login, calls don't work. Call screens may be blank or throw errors.
  • Cause: The Calls SDK maintains its own session state. After CometChatUIKit.logout(), the Calls SDK session is invalidated but may not be properly re-initialized on the next login.
  • Fix: Ensure the Calls SDK is re-initialized after login. The UIKit handles this internally — if you're managing calls manually, call the Calls SDK init after each successful login.

4.7 Outgoing call screen never renders / app shows nothing after tapping call (V6 navigatorKey trap)

  • Symptom: Caller taps the call button. The peer rings (server received the call). The caller's Flutter app shows nothing — no outgoing-call screen, no error in onSuccess/onError. CometChat.initiateCall returns successfully with a valid sessionId, but no UI ever appears.
  • Cause: MaterialApp is missing navigatorKey: CallNavigationContext.navigatorKey. The kit's CometChatCallButtons and outgoing-call flow navigate via CallNavigationContext.navigatorKey.currentContext — which is null until the app's MaterialApp is wired to that key. The failure is silent because initiateCall itself succeeds; only the navigation to the outgoing-call screen fails. Important: the vendor's own 6.0.1 sample app is missing this line, so customers who copied main.dart verbatim will hit this bug. This is the single most common customer-blocking V6 calls trap.
  • Fix: Wire CallNavigationContext.navigatorKey on the root MaterialApp:
// ✅ CORRECT — navigatorKey wired on MaterialApp
import 'package:flutter/material.dart';
import 'package:cometchat_chat_uikit/cometchat_calls_uikit.dart'
    show CallNavigationContext;  // calls is a sub-library of cometchat_chat_uikit — there is NO separate cometchat_calls_uikit package in v6

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: CallNavigationContext.navigatorKey, // REQUIRED for V6 calls
      home: const HomeScreen(),
    );
  }
}

// ❌ WRONG — no navigatorKey; outgoing-call screen never appears
return MaterialApp(
  home: const HomeScreen(),
);

See cometchat-flutter-v6-calls §1.7 for the canonical wiring rule.

4.8 Stuck on "Calling…" after peer accepts (v6.0.0-beta2 BLoC bug — fixed in 6.0.1)

  • Symptom: Outgoing call screen displays correctly, peer accepts the call, but the caller's screen stays stuck on "Calling…" and never transitions to the in-call surface. Audio/video may already be flowing in the background; only the UI state is wrong.
  • Cause: A known BLoC transition bug in cometchat_chat_uikit ^6.0.0-beta2 where the outgoing → in-call state never fires. This is FIXED in 6.0.1 GA.
  • Fix: Upgrade to cometchat_chat_uikit ^6.0.1 (or the latest 6.x):
# pubspec.yaml
dependencies:
  cometchat_chat_uikit: ^6.0.1  # was ^6.0.0-beta2

Then run:

flutter pub get
flutter clean
flutter run

If the bug persists after upgrade, verify Section 4.7 (navigatorKey is still required on 6.0.1).


5. Listener Issues

5.1 Duplicate events (hardcoded listener IDs)

  • Symptom: Event handlers fire multiple times for a single event. Messages appear twice, typing indicators flicker.
  • Cause: Listener registered with a hardcoded ID. When the widget is recreated (e.g., navigation), the new listener overwrites the old one but the old widget's handler may still be referenced, or multiple instances collide.
  • Fix: Use a unique listener ID per widget instance:
// ✅ CORRECT — unique ID per instance
class _MyScreenState extends State<MyScreen> with MessageListener {
  late final String _listenerId;

  @override
  void initState() {
    super.initState();
    _listenerId = 'my_screen_${DateTime.now().millisecondsSinceEpoch}';
    CometChat.addMessageListener(_listenerId, this);
  }

  @override
  void dispose() {
    CometChat.removeMessageListener(_listenerId);
    super.dispose();
  }
}

// ❌ WRONG — hardcoded ID causes collisions across instances
CometChat.addMessageListener('messages', this); // Collision!

5.2 Listener leaks (missing dispose)

  • Symptom: Memory usage grows over time. Events fire on screens that are no longer visible. App becomes sluggish.
  • Cause: SDK listeners registered in initState() but not removed in dispose().
  • Fix: Always remove listeners with the same ID used to register:
@override
void dispose() {
  CometChat.removeMessageListener(_listenerId);
  CometChat.removeUserListener(_listenerId);
  CometChat.removeGroupListener(_listenerId);
  CometChat.removeCallListener(_listenerId);
  super.dispose();
}

5.3 No events firing (subscriptionType not set)

  • Symptom: All listeners are properly registered and removed, but no events ever fire. No errors in console.
  • Cause: subscriptionType not set in UIKitSettingsBuilder. This silently disables all real-time events.
  • Fix: Set subscriptionType during init:
UIKitSettingsBuilder()
  ..subscriptionType = CometChatSubscriptionType.allUsers

6. Build Errors

6.0 pub get can't resolve cometchat_chat_uikit ^6.x / resolves a beta

  • Symptom: flutter pub get fails to find cometchat_chat_uikit ^6.0.x, or pulls a 6.0.0-beta instead of the GA.
  • Cause: Wrong package source. The v6 GA is on pub.dev; Cloudsmith hosts only the beta + legacy V5.
  • Fix: Use the default pub.dev source — dependencies: cometchat_chat_uikit: ^6.0.2 (no hosted: block). Only add the Cloudsmith hosted: URL if you are intentionally on a beta/V5. (V6 calls fold into this one package — there is no separate cometchat_calls_uikit package on v6; calls types come from the package:cometchat_chat_uikit/cometchat_calls_uikit.dart sub-library.)

6.05 Push token never registers / looking for PNRegistry

  • Symptom: Push notifications never arrive; code references a PNRegistry class that won't import.
  • Cause: PNRegistry is not a kit/SDK symbol — it's a copy-in V5 sample-app extension (extension PNRegistry on CometChatService), not exported by any cometchat_* package.
  • Fix: The real push API is CometChatNotifications.registerPushToken(PushPlatforms.FCM_FLUTTER_ANDROID, fcmToken: token, providerId: ...) (+ FCM_FLUTTER_IOS / APNS_FLUTTER_DEVICE / APNS_FLUTTER_VOIP) — call it AFTER login, and unregisterPushToken(...) on logout. See cometchat-flutter-v6-push.

6.1 Android: ClassNotFoundException (missing ProGuard rules)

  • Symptom: Release build crashes with ClassNotFoundException for CometChat classes. Debug builds work fine.
  • Cause: R8/ProGuard strips CometChat SDK classes during release minification.
  • Fix: Create android/app/proguard-rules.pro with:
# CometChat — prevent R8 from stripping SDK classes
-keep class com.cometchat.** { *; }
-keep interface com.cometchat.** { *; }

# Suppress warnings for Calls SDK classes referenced cross-module
-dontwarn com.cometchat.calls.CometChatRTCView$CometChatRTCViewBuilder
-dontwarn com.cometchat.calls.CometChatRTCView
-dontwarn com.cometchat.calls.CometChatRTCViewListener
-dontwarn com.cometchat.calls.model.AnalyticsSettings
-dontwarn com.cometchat.calls.model.RTCCallback
-dontwarn com.cometchat.calls.model.RTCReceiver

Reference it in android/app/build.gradle:

buildTypes {
    release {
        isMinifyEnabled = true
        isShrinkResources = true
        proguardFiles(
            getDefaultProguardFile("proguard-android-optimize.txt"),
            "proguard-rules.pro"
        )
    }
}

6.2 Android: minSdk too low

  • Symptom: Build fails with error about minimum SDK version. Error mentions minSdkVersion incompatibility.
  • Cause: minSdk is set below 26. The cometchat_calls_sdk requires minSdk 26.
  • Fix: In android/app/build.gradle (or .kts):
defaultConfig {
    minSdk = 26  // Required by cometchat_calls_sdk
}

6.3 Android: Jetifier missing

  • Symptom: Build fails with errors about Android Support Library classes not found, or androidx conflicts.
  • Cause: android.enableJetifier=true not set. Transitive dependencies from the CometChat SDK use old Android Support Library references.
  • Fix: In android/gradle.properties:
android.useAndroidX=true
android.enableJetifier=true

6.4 iOS: pod install failures

  • Symptom: pod install fails with dependency resolution errors, version conflicts, or missing pods.
  • Cause: Cocoapods cache is stale, or the Podfile needs updating.
  • Fix:
cd ios
rm -rf Pods Podfile.lock
pod repo update
pod install --repo-update
cd ..
flutter clean
flutter pub get

If still failing, check that the iOS deployment target in ios/Podfile is high enough:

platform :ios, '13.0'  # Minimum for CometChat

6.5 iOS: missing permissions

  • Symptom: App crashes or shows blank screen when trying to access camera, microphone, or photo library on iOS.
  • Cause: Required permission descriptions missing from Info.plist.
  • Fix: Add to ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera access is needed for video calls and sending photos</string>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is needed for voice and video calls</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Photo library access is needed for sending images</string>

For VoIP calls, also add:

<key>UIBackgroundModes</key>
<array>
    <string>voip</string>
    <string>remote-notification</string>
</array>

6.6 Android: KGP "legacy plugin application" warning (benign)

  • Symptom: flutter build apk / flutter run prints a warning that the CometChat plugins apply the Kotlin Gradle Plugin the legacy way (e.g. "The Kotlin Gradle plugin was loaded multiple times…" / legacy-plugin-application deprecation from both cometchat_chat_uikit and cometchat_calls_sdk).
  • Cause: kit-side — the plugins haven't migrated to the declarative plugins {} KGP application. It's emitted by the kit, not your project.
  • Fix: None needed — this is a warning, not an error. The build still succeeds (verified — real flutter build apk --debug). Don't try to "fix" it in your app; it clears when the kit updates its Gradle plugin wiring.

7. Performance Issues

7.1 Theme lookup in build() causing jank

  • Symptom: Dropped frames during scrolling or keyboard animation. Flutter DevTools shows long build times (44–95ms).
  • Cause: CometChatThemeHelper.getColorPalette(context) and similar calls in build() do expensive InheritedWidget traversal on every rebuild.
  • Fix: Cache theme values in didChangeDependencies() — see Section 3.5 for the full pattern. For child widgets, pass pre-cached theme values from the parent:
// Parent passes cached values to children
CometChatImageBubble(
  imageUrl: message.attachment?.fileUrl,
  colorPalette: _colorPalette,  // Pre-cached from parent
  spacing: _spacing,            // Pre-cached from parent
);

7.2 Missing buildWhen optimization

  • Symptom: Entire widget tree rebuilds on every BLoC state change, even when only a small part of the state changed.
  • Cause: BlocConsumer or BlocBuilder without buildWhen — rebuilds on every state emission.
  • Fix: Add buildWhen to limit rebuilds to relevant state changes:
BlocConsumer<MessageComposerBloc, MessageComposerState>(
  buildWhen: (previous, current) =>
      previous.isEditMode != current.isEditMode ||
      previous.isReplyMode != current.isReplyMode ||
      previous.isRecordingMode != current.isRecordingMode ||
      previous.editMessage != current.editMessage ||
      previous.replyMessage != current.replyMessage,
  listener: (context, state) { /* still receives ALL state changes */ },
  builder: (context, state) { /* only rebuilds when buildWhen is true */ },
)

7.3 O(n) lookups instead of O(1)

  • Symptom: Slow scrolling in long message lists. findChildIndexCallback takes too long.
  • Cause: Using list.indexWhere() (O(n)) to find messages instead of a Map-based O(1) lookup.
  • Fix: Maintain a Map<int, int> alongside the message list for O(1) index lookups:
// In BLoC — maintain O(1) lookup map
final Map<int, int> _messageIndexMap = {};

int? findMessageIndex(int messageId) => _messageIndexMap[messageId];

// In SliverAnimatedList
SliverAnimatedList(
  findChildIndexCallback: (Key key) {
    if (key is ValueKey<int>) {
      final index = widget.findMessageIndex?.call(key.value) ??
          _messages.indexWhere((m) => m.id == key.value);
      if (index != -1) return visualPosition(index);
    }
    return null;
  },
)

8. Platform-Specific Issues

8.1 Android-specific

SymptomCauseFix
Release crash ClassNotFoundExceptionMissing ProGuard rulesAdd -keep class com.cometchat.** { *; } — see Section 6.1
Build fail minSdkminSdk < 26Set minSdk = 26 in build.gradle
Build fail support libraryMissing JetifierAdd android.enableJetifier=true to gradle.properties
startSession returns nullKnown Calls SDK issueImplement timeout + retry — see Section 4.4
CallManager not foundNative module not linkedClean build + verify ProGuard + Jetifier — see Section 4.3
Audio recording stuck after permissionPermission callback raceEnsure permission is granted before starting recording; handle the permission result callback properly

8.2 iOS-specific

SymptomCauseFix
Pod install failsStale cache or version conflictrm -rf Pods Podfile.lock && pod install --repo-update
Camera/mic crashMissing Info.plist permissionsAdd NSCameraUsageDescription, NSMicrophoneUsageDescription — see Section 6.5
Media not sendingFile access or permission issueVerify NSPhotoLibraryUsageDescription in Info.plist; check file picker permissions
App crash on iPhone 11Device-specific compatibilityCheck iOS deployment target ≥ 13.0; verify no 32-bit dependencies
VoIP calls not received in backgroundMissing background modesAdd voip and remote-notification to UIBackgroundModes in Info.plist

8.3 Web-specific

SymptomCauseFix
Runtime error on webPlatform-specific code without kIsWeb guardWrap platform-specific code with if (!kIsWeb) checks
Native plugins crash on webPlugin not available on webUse conditional imports or kIsWeb guards before calling native APIs
CORS errorsAPI calls blocked by browserEnsure CometChat API endpoints are accessible; check proxy configuration
// ✅ CORRECT — guard platform-specific code
import 'package:flutter/foundation.dart' show kIsWeb;

if (!kIsWeb) {
  // Native-only code (e.g., push notifications, file system access)
  setupPushNotifications();
}

// For conditional imports:
// lib/platform/native_service.dart — native implementation
// lib/platform/web_service.dart — web implementation

Quick Reference: Error → Fix Table

Error / SymptomSectionOne-Line Fix
"Authentication null"2.1Call CometChatUIKit.init() before any usage
"APP ID null"2.2Set ..appId = 'YOUR_APP_ID' in UIKitSettingsBuilder
ERR_ALREADY_LOGGED_IN2.3Check CometChatUIKit.loggedInUser before calling login
"Android internal error"2.4Verify credentials, UID existence, try stable SDK
Guard screen stuck on spinner2.5Use CometChatUIKit.loggedInUser synchronously after init
ERR_INVALID_REGION2.6Use lowercase: 'us', 'eu', 'in'
StateError: not initialized2.7Call ServiceLocator.instance.setup() before creating BLoC
Double keyboard compensation (pre-6.0.1)3.1Upgrade kit to ^6.0.1 (composer clamps to viewInsets, ENG-34434); keep resizeToAvoidBottomInset: true. false is only an old-kit stopgap
No typing indicators / presence3.3Set ..subscriptionType = CometChatSubscriptionType.allUsers
Theme jank during keyboard3.5Cache theme in didChangeDependencies(), not build()
Outgoing call screen never appears4.7Wire navigatorKey: CallNavigationContext.navigatorKey on MaterialApp
Stuck on "Calling…" after peer accepts4.8Upgrade cometchat_chat_uikit from ^6.0.0-beta2 to ^6.0.1
Duplicate events5.1Use unique listener ID per widget instance
Listener leak5.2Remove listener in dispose() with same ID
ClassNotFoundException (release)6.1Add ProGuard keep rules for com.cometchat.**
minSdk too low6.2Set minSdk = 26
Jetifier missing6.3Add android.enableJetifier=true
Pod install failure6.4Delete Pods + Podfile.lock, pod install --repo-update
Missing iOS permissions6.5Add camera/mic/photo descriptions to Info.plist

Checklist — Every CometChat Integration

Use this checklist to verify your integration is correct:

  • CometChatUIKit.init() called and awaited before any usage
  • Auth check uses CometChatUIKit.loggedInUser after init (not CometChat.getLoggedInUser())
  • subscriptionType set in UIKitSettingsBuilder
  • region is lowercase ('us', 'eu', 'in')
  • Scaffold hosting CometChatMessageComposer uses resizeToAvoidBottomInset: true (or omits it) on ^6.0.1 — composer clamps to viewInsets (ENG-34434); false is only the pre-6.0.1 stopgap
  • Theme cached in didChangeDependencies(), not build()
  • SDK listeners registered with unique ID, removed in dispose()
  • Colors from CometChatThemeHelper, never hardcoded
  • Strings from Translations.of(context), never hardcoded
  • If using calls: MaterialApp wires navigatorKey: CallNavigationContext.navigatorKey (required for V6 calls, including 6.0.1)
  • If using calls on 6.0.0-beta2: upgrade to cometchat_chat_uikit ^6.0.1 (fixes outgoing → in-call BLoC transition)
  • Android: minSdk ≥ 26, Jetifier enabled, ProGuard rules added
  • iOS: permissions in Info.plist, deployment target ≥ 13.0
  • Web: kIsWeb guards on platform-specific code

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.