flutterfire icon indicating copy to clipboard operation
flutterfire copied to clipboard

🐛 [cloud_firestore_odm] Required data thrown exception although not expected

Open Purus opened this issue 3 years ago • 2 comments

Bug report

As per the examples, checks for snapshot.hasError and !snapshot.hasData is already done before using the data. But still I get the below exception which checks for error and data.

My understanding is that it shouldn't be reached to call snapshot.requireData due to validations in previous lines.

return FirestoreBuilder<AppUserQuerySnapshot>(
      ref: usersRef
          .orderById()
          .orderByJoinDate(descending: true)
          .whereIsActive(isEqualTo: true)
          .whereId(isNotEqualTo: FirebaseAuth.instance.currentUser?.uid),
      builder: (context, AsyncSnapshot<AppUserQuerySnapshot> snapshot,
          Widget? child) {
        if (snapshot.hasError) {
          return Container(
            height: 0,
          );
        }

        if (!snapshot.hasData) {
          const Center(
            child: CircularProgressIndicator.adaptive(),
          );
        }

        AppUserQuerySnapshot querySnapshot = snapshot.requireData;

        List<Widget> usersList = querySnapshot.docs.map((e) {
          AppUser user = e.data;

          return InkWell(
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: AppUserAvatar(user),
            ),
            onTap: () => context.push('/profile/${user.id}'),
          );
        }).toList();

        return ListView(
          scrollDirection: Axis.horizontal,
          children: usersList,
        );
      },
    );

Error which I am getting for a brief moment before rendering the actual content is given below.

======== Exception caught by widgets library =======================================================
The following StateError was thrown building FirestoreBuilder<AppUserQuerySnapshot>(dirty, state: _FirestoreBuilderState<AppUserQuerySnapshot>#924ce):
Bad state: Snapshot has neither data nor error

The relevant error-causing widget was: 
  FirestoreBuilder<AppUserQuerySnapshot> FirestoreBuilder:file:///D:/flutter/mozhli/lib/ui/home/widgets/recent_users_widget.dart:14:12
When the exception was thrown, this was the stack: 
#0      AsyncSnapshot.requireData (package:flutter/src/widgets/async.dart:255:5)
#1      RecentUsersWidget.build.<anonymous closure> (package:mozhli/ui/home/widgets/recent_users_widget.dart:35:55)
#2      _FirestoreBuilderState.build (package:cloud_firestore_odm/src/firestore_builder.dart:133:26)
#3      StatefulElement.build (package:flutter/src/widgets/framework.dart:4992:27)
#4      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4878:15)
#5      StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#6      Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#7      ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4859:5)
#8      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5041:11)
#9      ComponentElement.mount (package:flutter/src/widgets/framework.dart:4853:5)
...     Normal element mounting (10 frames)
#19     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16)
#20     MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6435:36)
#21     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6447:32)
...     Normal element mounting (25 frames)
#46     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16)
#47     MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6435:36)
#48     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6447:32)
...     Normal element mounting (135 frames)
#183    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16)

Expected behavior

If no data, progress indicator should be shown. IF error, widget should not be shown.

Flutter doctor

Run flutter doctor and paste the output below:

Click To Expand
C:\Users\Purus>flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.3.2, on Microsoft Windows [Version 10.0.22000.978], locale en-IN)
Checking Android licenses is taking an unexpectedly long time...[√] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.3.0)
[√] Android Studio (version 2021.2)
[√] IntelliJ IDEA Community Edition (version 2022.2)
[√] VS Code (version 1.71.0)
[√] Connected device (4 available)
[√] HTTP Host Availability

• No issues found!

C:\Users\Purus>

Flutter dependencies

Run flutter pub deps -- --style=compact and paste the output below:

Click To Expand
C:\Users\Purus>flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.3.2, on Microsoft Windows [Version 10.0.22000.978], locale en-IN)
Checking Android licenses is taking an unexpectedly long time...[√] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.3.0)
[√] Android Studio (version 2021.2)
[√] IntelliJ IDEA Community Edition (version 2022.2)
[√] VS Code (version 1.71.0)
[√] Connected device (4 available)
[√] HTTP Host Availability

• No issues found!

C:\Users\Purus>

Purus avatar Sep 20 '22 17:09 Purus

It'd help if you could share a complete example, or give more info (like sharing the AsyncSnapshot).

Otherwise I doubt we can do anything to help here, as it's unclear what happens.

rrousselGit avatar Sep 20 '22 19:09 rrousselGit

This is my model. Hope this is helpful. Not sure what you meant by AsyncSnapshot.

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:cloud_firestore_odm/cloud_firestore_odm.dart';
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';

part 'app_user.g.dart';

const fireStoreSerializable = JsonSerializable(
  converters: firestoreJsonConverters,
  explicitToJson: true,
  createFieldMap: true,
);

@fireStoreSerializable
class AppUser extends Equatable {
  const AppUser({
    required this.id,
    required this.name,
    required this.email,
    required this.photoUrl,
    required this.joinDate,
    this.birthDate,
    this.country,
    this.age = 0,
    this.isOnline = false,
    this.lastOnline,
    this.isAdmin = false,
    this.isActive = true,
    this.gender,
    this.tokens,
  });

  final String id;
  final String name;
  final String email;
  final String photoUrl;
  final Timestamp joinDate;
  final Timestamp? birthDate;
  final int age;
  final bool? isAdmin;
  final bool? isOnline;
  final Timestamp? lastOnline;
  final bool? isActive;
  final String? country;
  final String? gender;
  final List<String>? tokens;

  factory AppUser.fromJson(Map<String, Object?> json) =>
      _$AppUserFromJson(json);

  Map<String, Object?> toJson() => _$AppUserToJson(this);

  @override
  List<Object?> get props => [name, email, photoUrl];
}

@Collection<AppUser>('users')
// @Collection<AppUser>('users/*/friends')
final usersRef = AppUserCollectionReference();

Purus avatar Sep 21 '22 16:09 Purus

May I know if this is confirmed to a bug or an issue at my end? Other use cases of ODM seems to work fine for me.

Purus avatar Sep 24 '22 14:09 Purus

Hard to say. What you shared still isn't something we can run to reproduce the problem on our end, and you haven't shared your AsyncSnapshot as requested.

We'd need a complete example, with steps to reproduce and data.

To begin with, the source code of requireData is the following:

  T get requireData {
    if (hasData) {
      return data!;
    }
    if (hasError) {
      Error.throwWithStackTrace(error!, stackTrace!);
    }
    throw StateError('Snapshot has neither data nor error');
  }

So you're describing is not possible and there's likely more to it. But I can't guess what the problem is with the information given.

rrousselGit avatar Sep 25 '22 11:09 rrousselGit

Yea, I understand the problem of debugging the issue without actual example. My project is quite unorganized now and hard to seperate the issue.

For now, I have made the below changes as the connection state is still loading when the issue occurs. So to avoid, have put the below check. I can close this issue as this could be due to something I have done from my end.

        if (snapshot.data?.docs.isEmpty ?? true) {
          return const Padding(
            padding: EdgeInsets.only(top: 8.0),
            child: Text('No users yet. Please come back.'),
          );
        }

        AppUserQuerySnapshot querySnapshot = snapshot.requireData;

Purus avatar Sep 25 '22 12:09 Purus