Fixing Invalid Argument in Freezed

 ・ 3 min

photo by Jasper Gribble on Unsplash

I'm using the freezed and json_serializable packages when creating domain objects in Flutter. However, when certain classes depend on other classes, converting those objects to a Map using toJson and then trying to save them to Firebase's Firestore triggered the following error:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument: Instance of '_$TimeSlotImpl'

The WhenToMeet object that caused the error looks like this. The TimeSlot object was the problematic one.

@freezed
class WhenToMeet with _$WhenToMeet {
  const factory WhenToMeet({
    required WhenToMeetID id,
    required String title,
    required UserID creator,
    required List<User> invitees,
    required List<User> attendees,
    required Map<DateTime, Set<TimeSlot>> availableTimes,
    required Map<UserID, Map<DateTime, TimeSlot>> selectedTimes,
  }) = _WhenToMeet;

Debugging this error wasn't easy. _$TimeSlotImpl was created in the freezed.dart file generated by build_runner and referenced in the g.dart file. Since I didn't create it myself, I was puzzled about why the error was occurring. So I used print statements to check what the toJson result looked like.

image

If it were proper JSON, there shouldn't be any object information — but it was showing TimeSlot and TimeOfDay object information as if it was toString output, which seemed wrong.

After Googling, I found a similar issue on the freezed GitHub repository. Turns out this wasn't really a freezed problem but rather a json_serializable configuration issue.

Since I'm using build_runner, I created a build.yaml file in the Flutter project root to fix this. Then I added the following content:

targets:
  $default:
    builders:
      json_serializable:
        options:
          explicit_to_json: true

If you have build_runner running in watch mode, the generated files will be automatically deleted and recreated. If you try toJson again, you'll see that nested objects are now properly converted to JSON format — unlike before!

image

This might be unrelated to the issue above, but inside TimeSlot I was using Flutter's built-in TimeOfDay object, which didn't serialize well with toJson. So I implemented a JsonConverter called _TimeOfDayConverter and used it like this:

@freezed
class TimeSlot with _$TimeSlot {
  @Assert('start.compareTo(end) != 0', 'start must be earlier than end.')
  factory TimeSlot({
    @_TimeOfDayConverter() required TimeOfDay start,
    @_TimeOfDayConverter() required TimeOfDay end,
  }) = _TimeSlot;

A room without books is like a body without a soul.

— Marcus Tullius Cicero


Other posts
Fixing RenderFlex Overflow Caused by Virtual Keyboard in Flutter 커버 이미지
 ・ 4 min

Fixing RenderFlex Overflow Caused by Virtual Keyboard in Flutter

The Rise and Fall of Great Powers 커버 이미지
 ・ 20 min

The Rise and Fall of Great Powers

Fixing the Keychain Password Popup Error 커버 이미지
 ・ 2 min

Fixing the Keychain Password Popup Error