Skip to content
This repository has been archived by the owner on May 13, 2023. It is now read-only.

RealtimeSubscription Unhandled Exception: type 'Null' is not a subtype of type 'List<dynamic>' in type cast #64

Closed
offline-first opened this issue Nov 29, 2021 · 10 comments
Labels
bug Something isn't working

Comments

@offline-first
Copy link
Contributor

Bug report

When I listen to realtime events, and insert data to table, the supabase_realtime_payload.dart throws this exception.

[VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: type 'Null' is not a subtype of type 'List<dynamic>' in type cast
#0      new SupabaseRealtimePayload.fromJson.<anonymous closure> (package:supabase/src/supabase_realtime_payload.dart:36:35)
supabase/supabase-flutter#1      WhereIterator.moveNext (dart:_internal/iterable.dart:439:13)
supabase/supabase-flutter#2      MappedIterator.moveNext (dart:_internal/iterable.dart:390:19)
supabase/supabase-flutter#3      new _GrowableList._ofOther (dart:core-patch/growable_array.dart:198:26)
supabase/supabase-flutter#4      new _GrowableList.of (dart:core-patch/growable_array.dart:152:26)
supabase/supabase-flutter#5      new List.of (dart:core-patch/array_patch.dart:50:28)
supabase/supabase-flutter#6      Iterable.toList (dart:core/iterable.dart:388:12)
supabase/supabase-flutter#7      new SupabaseRealtimePayload.fromJson (package:supabase/src/supabase_realtime_payload.dart:38:10)
supabase/supabase-flutter#8      SupabaseRealtimeClient.on.<anonymous closure> (package:supabase/src/supabase_realtime_client.dart:35:57)
supabase/supabase-flutter#9      RealtimeSubscription.trigger (package:realtime_client/src/realtime_subscription.dart:221:20)
supabase/supabase-flutter#10     RealtimeClient.onConnMessage.<anonymous closure>.<anonymous closure> (package:realtime_client/src/realtime_client.dart:265:34)
supabase/supabase-flutter#11     Iterable.forEach (dart:core/iterable.dart:279:35)
supabase/supabase-flutter#12     RealtimeClient.onConnMessage.<anonymous closure> (package:realtime_client/src/realtime_client.dart:264:60)
supabase/supabase-flutter#13     new RealtimeClient.<anonymous closure> (package:realtime_client/src/realtime_client.dart:86:21)
supabase/supabase-flutter#14     RealtimeClient.onConnMessage (package:realtime_client/src/realtime_client.dart:249:11)
supabase/supabase-flutter#15     RealtimeClient.connect.<anonymous closure> (package:realtime_client/src/realtime_client.dart:108:11)
supabase/supabase-flutter#16     _rootRunUnary (dart:async/zone.dart:1436:47)
supabase/supabase-flutter#17     _CustomZone.runUnary (dart:async/zone.dart:1335:19)
supabase/supabase-flutter#18     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
supabase/supabase-flutter#19     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
supabase/supabase-flutter#20     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
supabase/supabase-flutter#21     _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
supabase/supabase-flutter#22     _HandleErrorStream._handleData (dart:async/stream_pipe.dart:253:10)
supabase/supabase-flutter#23     _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
supabase/supabase-flutter#24     _rootRunUnary (dart:async/zone.dart:1436:47)
supabase/supabase-flutter#25     _CustomZone.runUnary (dart:async/zone.dart:1335:19)
supabase/supabase-flutter#26     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
supabase/supabase-flutter#27     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
supabase/supabase-flutter#28     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
supabase/supabase-flutter#29     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
supabase/supabase-flutter#30     _StreamController._add (dart:async/stream_controller.dart:607:7)
supabase/supabase-flutter#31     _rootRunUnary (dart:async/zone.dart:1436:47)
supabase/supabase-flutter#32     _CustomZone.runUnary (dart:async/zone.dart:1335:19)
supabase/supabase-flutter#33     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
supabase/supabase-flutter#34     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
supabase/supabase-flutter#35     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
supabase/supabase-flutter#36     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
supabase/storage-dart#16     _StreamController._add (dart:async/stream_controller.dart:607:7)
supabase/supabase-flutter#38     _StreamController.add (dart:async/stream_controller.dart:554:5)
supabase/supabase-flutter#39     new _WebSocketImpl._fromSocket.<anonymous closure> (dart:_http/websocket_impl.dart:1150:21)
supabase/supabase-flutter#40     _rootRunUnary (dart:async/zone.dart:1436:47)
supabase/supabase-flutter#41     _CustomZone.runUnary (dart:async/zone.dart:1335:19)
supabase/supabase-flutter#42     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
supabase/supabase-flutter#43     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
supabase/supabase-flutter#44     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
supabase/supabase-flutter#45     _SinkTransformerStreamSubscription._add (dart:async/stream_transformers.dart:63:11)
supabase/supabase-flutter#46     _EventSinkWrapper.add (dart:async/stream_transformers.dart:13:11)
supabase/supabase-flutter#47     _WebSocketProtocolTransformer._messageFrameEnd (dart:_http/websocket_impl.dart:338:23)
supabase/supabase-flutter#48     _WebSocketProtocolTransformer.add (dart:_http/websocket_impl.dart:232:46)
supabase/supabase-flutter#49     _SinkTransformerStreamSubscription._handleData (dart:async/stream_transformers.dart:111:24)
supabase/supabase-flutter#50     _rootRunUnary (dart:async/zone.dart:1436:47)
#51     _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#52     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
#53     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
#54     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
#55     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
#56     _StreamController._add (dart:async/stream_controller.dart:607:7)
#57     _StreamController.add (dart:async/stream_controller.dart:554:5)
#58     _Socket._onData (dart:io-patch/socket_patch.dart:2166:41)
#59     _rootRunUnary (dart:async/zone.dart:1436:47)
#60     _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#61     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
#62     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
#63     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
#64     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
#65     _StreamController._add (dart:async/stream_controller.dart:607:7)
#66     _StreamController.add (dart:async/stream_controller.dart:554:5)
#67     _RawSecureSocket._sendReadEvent (dart:io/secure_socket.dart:991:19)
#68     _rootRun (dart:async/zone.dart:1420:47)
#69     _CustomZone.run (dart:async/zone.dart:1328:19)
#70     _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#71     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
#72     _rootRun (dart:async/zone.dart:1428:13)
#73     _CustomZone.run (dart:async/zone.dart:1328:19)
#74     _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1260:23)
#75     Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
#76     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:395:19)
#77     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:426:5)
#78     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

Reproduce

Backend: https://github.com/supabase/supabase/tree/master/examples/nextjs-slack-clone

Flutter

// subscribe to messages
_messageListener = client
        .from('messages')
        .on(SupabaseEventTypes.insert, (payload) => print('newRecord:${payload.newRecord}'))
        .subscribe();
// insert message
addMessage(String message, int channelId)async{
    final response = await client
        .from('messages')
        .insert({ 'message' : message, 'user_id':  client.auth.currentUser!.id, 'channel_id': channelId})
        .execute();
  }

plugin version:

  • supabase: ^0.2.9
  • flutter sdk: ">=2.12.0 <3.0.0"
  • Platform: iOS 15.1
@bdlukaa
Copy link
Contributor

bdlukaa commented Nov 29, 2021

https://github.com/supabase/supabase-dart/blob/main/lib/src/supabase_realtime_payload.dart#L35-L38

@offline-first
Copy link
Contributor Author

Here is a fix:

final primaryKeys = (json['columns'] as List)
        .where((e) => (e['flags'] as List?)?.contains('key') == true)
        .map((e) => e['name'] as String)
        .toList();

@bdlukaa
Copy link
Contributor

bdlukaa commented Nov 29, 2021

@dshukertjr what do you think?

@offline-first

This comment has been minimized.

@bdlukaa bdlukaa transferred this issue from supabase/supabase-flutter Nov 30, 2021
@dshukertjr
Copy link
Member

dshukertjr commented Nov 30, 2021

Sorry for the late reply!

@offline-first Yup, your fix looks amazing! Would you like to open a PR this repo?

@dshukertjr
Copy link
Member

@offline-first BTW, I wonder why e['flags'] was null in your case. Would you be able to share the scheme of your messages table?

@offline-first
Copy link
Contributor Author

@dshukertjr PR is on the way

create table public.messages (
  id            bigint generated by default as identity primary key,
  inserted_at   timestamp with time zone default timezone('utc'::text, now()) not null,
  message       text,
  user_id       uuid references public.users not null,
  channel_id    bigint references public.channels on delete cascade not null
);
comment on table public.messages is 'Individual messages sent by each user.';

@offline-first
Copy link
Contributor Author

@dshukertjr
#65

@w3b6x9
Copy link
Member

w3b6x9 commented Dec 1, 2021

@offline-first BTW, I wonder why e['flags'] was null in your case. Would you be able to share the scheme of your messages table?

@dshukertjr Realtime Security (WALRUS) no longer sends flags but the old Realtime still does. I think #65 will help to maintain backwards compatibility.

@burggraf
Copy link
Member

burggraf commented Dec 1, 2021

I'm watching this.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants