Firebase Auth errors not being caught + weird errors

Issue

I’m working on a project that requires Firebase Auth.

When I try to catch an error when an email that’s already in use, I get the error in the console, but the catch statement never gets executed. I also (always) get a weird null value error, but that doesn’t seem to break anything.
The second error message is what I am focusing on.
Here are the error messages:

Error: Unexpected null value.
    at Object.throw_ [as throw] (http://localhost:33663/dart_sdk.js:5067:11)
    at Object.nullCheck (http://localhost:33663/dart_sdk.js:5394:30)
    at http://localhost:33663/packages/fischerliste/message_list.dart.lib.js:983:62
    at _RootZone.runUnary (http://localhost:33663/dart_sdk.js:40441:59)
    at _FutureListener.then.handleValue (http://localhost:33663/dart_sdk.js:35363:29)
    at handleValueCallback (http://localhost:33663/dart_sdk.js:35931:49)
    at Function._propagateToListeners (http://localhost:33663/dart_sdk.js:35969:17)
    at _Future.new.[_completeWithValue] (http://localhost:33663/dart_sdk.js:35817:23)
    at async._AsyncCallbackEntry.new.callback (http://localhost:33663/dart_sdk.js:35838:35)
    at Object._microtaskLoop (http://localhost:33663/dart_sdk.js:40708:13)
    at _startMicrotaskLoop (http://localhost:33663/dart_sdk.js:40714:13)
    at http://localhost:33663/dart_sdk.js:36191:9
Error: [firebase_auth/email-already-in-use] The email address is already in use by another account.
    at Object.throw_ [as throw] (http://localhost:33663/dart_sdk.js:5067:11)
    at firebase_auth_web.FirebaseAuthWeb.new.createUserWithEmailAndPassword (http://localhost:33663/packages/firebase_auth_web/firebase_auth_web.dart.lib.js:156:23)
    at createUserWithEmailAndPassword.throw (<anonymous>)
    at http://localhost:33663/dart_sdk.js:40576:38
    at _RootZone.runBinary (http://localhost:33663/dart_sdk.js:40445:59)
    at _FutureListener.thenAwait.handleError (http://localhost:33663/dart_sdk.js:35374:33)
    at handleError (http://localhost:33663/dart_sdk.js:35947:51)
    at Function._propagateToListeners (http://localhost:33663/dart_sdk.js:35973:17)
    at _Future.new.[_completeError] (http://localhost:33663/dart_sdk.js:35823:23)
    at async._AsyncCallbackEntry.new.callback (http://localhost:33663/dart_sdk.js:35859:31)
    at Object._microtaskLoop (http://localhost:33663/dart_sdk.js:40708:13)
    at _startMicrotaskLoop (http://localhost:33663/dart_sdk.js:40714:13)
    at http://localhost:33663/dart_sdk.js:36191:9

Here is my code:

(you can find everything at https://github.com/fischerliste/fischerliste/tree/master/lib)

import 'package:flutter/scheduler.dart';
import 'data/message_dao.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';

class MessageListState extends State<MessageList> {
  MessageListState();
  FirebaseApp app = Firebase.app();
  String? uid;
  SharedPreferences? prefs;
  FirebaseAuth auth = FirebaseAuth.instanceFor(app: Firebase.app());
  UserCredential? credential;

  @override
  void initState() {
    SharedPreferences.getInstance().then((SharedPreferences? value) {
      prefs = value;
      uid = prefs!.getString('UID');
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    if (uid == null) {
      SchedulerBinding.instance?.addPostFrameCallback((_) {
        Navigator.of(context)
            .push(showSigninPopup(context, auth))
            .then((value) {
          credential = value;
          prefs!.setString('UID', uid!);
          return uid = "1234test";
        });
      });
    }

    return Scaffold();
//layout code here removed to make it shorter, but in case you want to
//see it, github link can be found above.
  }
}

DialogRoute showSigninPopup(BuildContext buildcontext, FirebaseAuth auth) {
  UserCredential? credential;
  TextEditingController emailController = TextEditingController();
  TextEditingController passwordController = TextEditingController();

  bool createUser() {
    try {
      auth.createUserWithEmailAndPassword(
              email: emailController.text, password: passwordController.text)
          .then((UserCredential? value) {
        credential = value;
      });
    } catch (e) {
      print('==================');
      print('This never gets executed');
      print(e);
    }
    return true;
  }

  bool checkSignin() {
    try {
      auth.signInWithEmailAndPassword(
              email: emailController.text, password: passwordController.text)
          .then((value) {
        print(value);
      });
    } catch (exception) {
      print(exception);
    }
    return true;
  }

  return DialogRoute(
    barrierDismissible: false,
    builder: (context) {
      return AlertDialog(
        title: const Text("Bitte anmelden!"),
        content: Column(
          children: [
            TextField(
              controller: emailController,
              decoration: const InputDecoration(labelText: 'Email'),
            ),
            TextField(
              controller: passwordController,
              decoration: const InputDecoration(labelText: 'Passwort'),
              obscureText: true,
            ),
          ],
          mainAxisSize: MainAxisSize.min,
        ),
        actions: <Widget>[
          TextButton(
              onPressed: () {
                createUser();
                Navigator.pop(context);
              },
              child: const Text("Registrieren")),
          TextButton(
              onPressed: () {
                if (checkSignin()) {
                  Navigator.pop(context);
                }
              },
              child: const Text("Anmelden")),
        ],
      );
    },
    context: buildcontext,
  );
}

class MessageList extends StatefulWidget {
  MessageList({Key? key}) : super(key: key);
  final messageDao = MessageDao();

  @override
  MessageListState createState() => MessageListState();
}

Solution

The call to createUserWithEmailAndPassword returns a Future, which can either succeed or fail. But a failure of the Future only gets translates to an exception if you await the call.

So:

try {
    credential = await auth.createUserWithEmailAndPassword(
          email: emailController.text, password: passwordController.text);
} catch (e) {
  print('==================');
  print('This never gets executed');
  print(e);
}

If you’d like to learn more about this, I recommend watching this video: Firebase Authentication in Flutter (The Boring Flutter Development Show, Ep. 55) – YouTube.

Answered By – Frank van Puffelen

Answer Checked By – Jay B. (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *