Skip to content

[firebase_data_connect]: Converting List with Map values throws exception #17348

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
mcfrancho1 opened this issue May 12, 2025 · 6 comments · Fixed by #17356
Closed
1 task done

[firebase_data_connect]: Converting List with Map values throws exception #17348

mcfrancho1 opened this issue May 12, 2025 · 6 comments · Fixed by #17356
Labels
Needs Attention This issue needs maintainer attention. platform: all Issues / PRs which are for all platforms. plugin: data_connect type: bug Something isn't working

Comments

@mcfrancho1
Copy link

Is there an existing issue for this?

  • I have searched the existing issues.

Which plugins are affected?

Other

Which platforms are affected?

Android, iOS, macOS, Web

Description

When data is stored as jsonb (AnyValue) in data connect. During parsing of the data when querying, an exception is thrown when toJson() is called on the query result.

NoSuchMethodError: 'toJson'
Dynamic call of null.
Receiver: Instance of '_JsonMap'

After further investigations, it appears the error occurs in the AnyValue class at:

dynamic toJson() {
    if (value is bool || value is double || value is int || value is String) {
      return value;
    } else {
      if (value is List) {
        return (value as List).map((e) => e.toJson()).toList();
      } else if (value is Map) {
        // TODO(mtewani): Throw an error if this is the wrong type.
        return convertMap(value as Map<String, dynamic>);
      }
      try {
        return value.toJson();
      } catch (e) {
        // empty cache to try and encode the value
      }
      try {
        return value;
      } catch (e) {
        throw Exception('Could not encode type ${value.runtimeType}');
      }
    }
  }

When a list contains Map values, this error will always be thrown because dart Maps have no toJson() methods.

Reproducing the issue

Store the following data as jsonb(AnyValue) column to your table(business):
{ "0": { "isOpen": true, "dayIndex": "0", "availabilityHours": [ { "isOpen": true, "endTime": "11:59 PM", "dayIndex": "0", "startTime": "12:00 AM" } ] }, "1": { "isOpen": true, "dayIndex": "1", "availabilityHours": [ { "isOpen": true, "endTime": "11:59 PM", "dayIndex": "1", "startTime": "12:00 AM" } ] }, "2": { "isOpen": true, "dayIndex": "2", "availabilityHours": [ { "isOpen": true, "endTime": "11:59 PM", "dayIndex": "2", "startTime": "12:00 AM" } ] }, "3": { "isOpen": true, "dayIndex": "3", "availabilityHours": [ { "isOpen": true, "endTime": "11:59 PM", "dayIndex": "3", "startTime": "12:00 AM" } ] }, "4": { "isOpen": true, "dayIndex": "4", "availabilityHours": [ { "isOpen": true, "endTime": "11:59 PM", "dayIndex": "4", "startTime": "12:00 AM" } ] }, "5": { "isOpen": true, "dayIndex": "5", "availabilityHours": [ { "isOpen": true, "endTime": "11:59 PM", "dayIndex": "5", "startTime": "12:00 AM" } ] }, "6": { "isOpen": true, "dayIndex": "6", "availabilityHours": [ { "isOpen": true, "endTime": "11:59 PM", "dayIndex": "6", "startTime": "12:00 AM" } ] } }

Store AnyValue to data connect database. Make sure that your

Firebase Core version

3.9.0

Flutter Version

3.29.2

Relevant Log Output

NoSuchMethodError: 'toJson'
Dynamic call of null.
Receiver: Instance of '_JsonMap'
Arguments: []

Flutter dependencies

Expand Flutter dependencies snippet
  firebase_core: ^3.9.0
  firebase_crashlytics: ^4.3.4
  firebase_data_connect: ^0.1.4+1
  firebase_messaging: ^15.1.6
  firebase_storage: ^12.1.3
  cloud_firestore: ^5.6.0
  cloud_functions: ^5.2.0

Additional context and comments

No response

@mcfrancho1 mcfrancho1 added type: bug Something isn't working Needs Attention This issue needs maintainer attention. labels May 12, 2025
@SelaseKay SelaseKay added platform: all Issues / PRs which are for all platforms. plugin: data_connect labels May 13, 2025
@SelaseKay
Copy link
Contributor

Hi @mcfrancho1, could you provide a minimal code that reproduces this issue?

@SelaseKay SelaseKay added blocked: customer-response Waiting for customer response, e.g. more information was requested. and removed Needs Attention This issue needs maintainer attention. labels May 14, 2025
@mcfrancho1
Copy link
Author

@SelaseKay Yes, I have attached a sample code to reproduce this. The error is thrown when calling .toJson() on the query data returned. To reproduce, replace menu.availabilitySchedule with the json data attached above.

class MenuDBService {

//Dart Mutation
  Future<FoodMenu?> setMenu(FoodMenu menu, {String? firestoreId}) async {
    try {
      var res = await dbConnector
          .setMenu(
            id: menu.id,
            name: menu.name,
            active: menu.active,
            kitchenId: menu.kitchenId,
          )
          .availabilityScheduleJson(AnyValue(menu.availabilitySchedule))
          .firestoreId(firestoreId)
          .tag(menu.tag)
          .docRef(null)
          .execute();

      return menu.copyWith(id: res.data.menu_upsert.id);
    } catch (e) {
      print(e);
      return null;
    }
  }
}

//Dart query method using the generated sdk code
 Future<List<FoodMenu>> getKitchenCompleteMenus(String kitchenId) async {
    try {
      var res = await dbConnector
          .getKitchenCompleteMenus(kitchenId: kitchenId)
          .execute();

      List<FoodMenu> menus = [];
      for (var menu in res.data.menus) {
          print(menu.json());
      }
    }catch(e) {print(e);}
}
 # mutation.gql
mutation SetMenu(
    $id: UUID!
    $name: String!
    $docRef: String
    $firestoreId: String
    $kitchenId: String!
    $active: Boolean!
    $tag: String
    $availabilityScheduleJson: Any
) @auth(level: USER_EMAIL_VERIFIED, insecureReason: "All verified users are allowed to perform this operation") {
  menu_upsert(
    data: {
      id: $id
      active: $active, 
      availabilityScheduleJson: $availabilityScheduleJson,
      firestoreId: $firestoreId
      kitchenId: $kitchenId    
      docRef: $docRef, 
      name: $name, 
      tag: $tag, 
    }
  )
}

# queries.gql
query GetKitchenCompleteMenus($kitchenId: String!)  @auth(level: USER_EMAIL_VERIFIED, insecureReason: "All verified users are allowed to perform this operation") {
  menus (where: {kitchenId: {eq: $kitchenId}}){
    name
    docRef
    firestoreId
    active
    createdAt
    updatedAt
    availability
    subtitle
    tag
    experience
    availabilityScheduleJson
  }
}

@google-oss-bot google-oss-bot added Needs Attention This issue needs maintainer attention. and removed blocked: customer-response Waiting for customer response, e.g. more information was requested. labels May 14, 2025
@SelaseKay
Copy link
Contributor

If I’m understanding correctly, the issue should be reproducible by calling AnyValue(menu.availabilitySchedule).toJson().

@SelaseKay SelaseKay added blocked: customer-response Waiting for customer response, e.g. more information was requested. and removed Needs Attention This issue needs maintainer attention. labels May 14, 2025
@mcfrancho1
Copy link
Author

No, the issue should be reproducible when you call menu.toJson() in the for loop of the getKitchenCompleteMenus() method

@google-oss-bot google-oss-bot added Needs Attention This issue needs maintainer attention. and removed blocked: customer-response Waiting for customer response, e.g. more information was requested. labels May 14, 2025
@SelaseKay
Copy link
Contributor

Hi @mcfrancho1, thanks for the detailed report. I've created a PR to fix this.

@mcfrancho1
Copy link
Author

Cool! Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Attention This issue needs maintainer attention. platform: all Issues / PRs which are for all platforms. plugin: data_connect type: bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants