Summary When using Appwrite Cloud with the Flutter SDK (latest appwrite release: 21.4.0), Realtime crashes with:
#0 new RealtimeMessage.fromMap (package:appwrite/src/realtime_message.dart:57:47)```
The crash occurs as soon as a real Realtime event (`.create`, `.update`, `.delete`) is received. Heartbeat messages work fine.
This happens before the event reaches the userβs sub.stream.listen(...) callback.
**Environment**
- Appwrite Cloud
- Endpoint: https://cloud.appwrite.io/v1
- Flutter SDK: appwrite: 21.4.0
- Platform: Android (Flutter)
**Root Cause**
Inside the Flutter SDK, RealtimeMessage.fromMap assumes that:
events: List<String> channels: List<String>
However, under certain conditions, the Realtime WebSocket payload delivers `events` and/or `channels` as a Map instead of a `List`.
Because the SDK strictly casts:
(map['events'] as List)
it throws:
type '_Map<String, dynamic>' is not a subtype of type 'Iterable<dynamic>'
This indicates the parser is not tolerant to slight payload structure variations.
**Reproduction**
Minimal example:
final sub = realtime.subscribe([ 'databases.{dbId}.collections.{collectionId}.documents' ]);
sub.stream.listen((event) { print(event); });
As soon as a document `.create` or `.update` event is triggered,
the SDK crashes in `RealtimeMessage.fromMap`.
Proposed Fix (Robust Parsing)
Making RealtimeMessage.fromMap tolerant to both List and Map resolves the issue completely.
Example patch:
static List<String> _coerceStringList(dynamic v) {
if (v == null) return const [];
if (v is List) return v.map((e) => e.toString()).toList();
if (v is Map) return v.values.map((e) => e.toString()).toList();
return [v.toString()];
}
factory RealtimeMessage.fromMap(Map<String, dynamic> map) {
final dynamic data = map['data'];
final Map<String, dynamic> m =
data is Map<String, dynamic> ? data : map;
return RealtimeMessage(
events: _coerceStringList(m['events']),
payload: Map<String, dynamic>.from(m['payload'] ?? const {}),
channels: _coerceStringList(m['channels']),
timestamp: (m['timestamp'] ?? '').toString(),
);
}
After applying this change locally, Realtime works reliably without crashes.
Why This Matters
- The crash occurs before user code can handle errors.
- It makes Realtime unusable in production Flutter apps.
- The fix is small and backward-compatible.
- Making parsing tolerant prevents similar crashes in the future if payload shape slightly changes.
Recommended threads
- Opening Project I get "500 Internal Erro...
https://cloud.appwrite.io/console/project-fra-69521af1003b40c342b1/overview/platforms I want open my app now. how to fix this? I can't find solution to fix th...
- Realtime doesn't seem to work with Table...
Hi, I am trying to connect my tables rows with realtime on my react website, it connects, but I dont get the rows when a row is being created. I tried with Chan...
- Guidance to safely upgrade Appwrite to l...
One of my old Flutter projects runs on a DO self-hosted Appwrite. Currently it's on appwrite: ^15.0.2 dart_appwrite: ^15.0.0 The app is live on the Play Stor...