Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble with Dart Futures in Flutter : Failed assertion: line 146: '<optimized out>': is not true

I'm building a user authentication module for my app and I am running into trouble with some asynchronous code.

Firstly, here is the error that is thrown:

E/flutter (17162): [ERROR:flutter/shell/common/shell.cc(188)] Dart Error: Unhandled exception: E/flutter (17162): 'dart:async/future_impl.dart': Failed assertion: line 146: 'optimized out': is not true. E/flutter (17162): #0 _AssertionError._doThrowNew (dart:core/runtime/liberrors_patch.dart:40:39) E/flutter (17162): #1 _AssertionError._throwNew (dart:core/runtime/liberrors_patch.dart:36:5) E/flutter (17162): #2 _FutureListener.handleError (dart:async/future_impl.dart:146:14) E/flutter (17162): #3 Future._propagateToListeners.handleError (dart:async/future_impl.dart:654:47) E/flutter (17162): #4 Future._propagateToListeners (dart:async/future_impl.dart:675:24) E/flutter (17162): #5 Future._completeError (dart:async/future_impl.dart:494:5) E/flutter (17162): #6 _SyncCompleter._completeError (dart:async/future_impl.dart:55:12) E/flutter (17162): #7 _Completer.completeError (dart:async/future_impl.dart:27:5) E/flutter (17162): #8 _AsyncAwaitCompleter.completeError (dart:async/runtime/libasync_patch.dart:40:18) E/flutter (17162): #9 FirebaseAuth.signInWithEmailAndPassword (package:firebase_auth/firebase_auth.dart) E/flutter (17162): E/flutter (17162): #10 Session.login. (package:mood_map/utilities/session.dart:31:24) E/flutter (17162): #11 _RootZone.runUnary (dart:async/zone.dart:1379:54) E/flutter (17162): #12 _FutureListener.handleValue (dart:async/future_impl.dart:129:18) E/flutter (17162): #13 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:642:45) E/flutter (17162): #14 Future._propagateToListeners (dart:async/future_impl.dart:671:32) E/flutter (17162): #15 Future._complete (dart:async/future_impl.dart:476:7) E/flutter (17162): #16 _SyncCompleter.complete (dart:async/future_impl.dart:51:12) E/flutter (17162): #17 _AsyncAwaitCompleter.complete (dart:async/runtime/libasync_patch.dart:28:18) E/flutter (17162): #18 _completeOnAsyncReturn (dart:async/runtime/libasync_patch.dart:295:13) E/flutter (17162): #19 Session._checkUserAlreadyExists (package:mood_map/utilities/session.dart) E/flutter (17162): E/flutter (17162): #20 Session.login (package:mood_map/utilities/session.dart:27:11)

And here are the functions that are involved:

static final FirebaseAuth _authenticator = FirebaseAuth.instance;

static void login(BuildContext context, String email, String password) async {

email = email.trim();
password = password.trim();

//Check if the user already exists
await _checkUserAlreadyExists(email).then((exists) {

  if(exists) {

    _authenticator.signInWithEmailAndPassword(email: email, password: password)
        .then((FirebaseUser user) { _loginSuccess(); })
        .catchError((Error e) { _loginFailure(context); });

  } else {

    Utilities.showMessageDialog(context, "That user doesn't exist. Please create an account below.");

  }

});

} 

----------------------------------------------------------------------

static Future createUserAccount(BuildContext context, email, String password) async {

//Check if the user already exists
await _checkUserAlreadyExists(email).then((exists) {

  if(exists) {

    Utilities.showMessageDialog(context, "That user already exists. Please login or select another account.");
    AppNavigator.navigateToLoginScreen();

  } else {

    _authenticator.createUserWithEmailAndPassword(email: email, password: password)
        .then((FirebaseUser user) { _createUserSuccess(); })
        .catchError((Error e) { _createUserFailure(context); });

  }

});

}

In short, the call to _authenticator.signonWithEmailAndPassword() is failing. I know that the _authenticator instance is working with other functions so I know it isnt a problem with Firebase itself.

I am worried that I am doing something incorrectly by calling another asynchronous function, _authenticator.signonWithEmailAndPassword() from within another asynchronous function, _checkIfUserAlreadyExists(). It seems that this should be okay to do from within a .then() block from what I've read but the error message seems pretty insistent that it is something to do with the setup of the asynchronous nature of the function calls.

Thoughts?

like image 883
jared-nelsen Avatar asked Nov 08 '18 04:11

jared-nelsen


2 Answers

If you use .then() clauses don't use await.

.then() and await are two different ways to handle Future's but shouldn't be used for the same Future instance.

like image 65
chemamolins Avatar answered Nov 09 '22 10:11

chemamolins


Consider using async - await to catch the errors in the 'final step'. This answer https://github.com/flutter/flutter/issues/22734 helped me a lot.

Below is a code snippet I got from a source I can't remember but it helped me understand how to properly work with Futures. I modified it a little bit to test for my exact situation (added main4() and divideFullAsyncNested() functions). I hope it helps.

// SO 29378453
import 'dart:async';

import 'package:login_app/constants.dart';

main() {
  // fails
  main1();
  main2();
  main3();
  main4();
}

Future<double> divide(int a, b) {
  // this part is still sync
  if (b == 0) {
    throw new Exception('Division by zero divide non-async');
  }
  // here starts the async part
  return new Future.value(a / b);
}

Future<double> divideFullAsync(int a, b) {
  return new Future(() {
    if (b == 0) {
      throw new Exception('Division by zero full async');
    }
    return new Future.value(a / b);
    // or just
    // return a / b;
  });
}

Future<double> divideFullAsyncNested() {
  return divideFullAsync(7, 8).then(
    (val) {
      return divideFullAsync(5, 0).then(
        (val2) {
          return Future(() {
            if (val2 == 1) {
              throw Exception('Innermost: Result not accepted exception.');
            }
            return val2;
          });
        },
      ).catchError((err) => throw Exception('Inner:    $err'));
    },
  ).catchError((err) => throw Exception('Outter: $err'));
}

//Future<double> divideFullAsyncNested() {
//  return divideFullAsync(9, 9).then(
//    (val) {
//      return Future(
//        () {
//          if (val == 1) {
//            throw Exception('Result not accepted exception.');
//          }
//          return val;
//        },
//      );
//    },
//  ).catchError((err) => throw Exception(err.toString()));
//}

// async error handling doesn't catch sync exceptions

void main1() async {
  try {
//    divide(1, 0).then((result) => print('(1) 1 / 0 = $result')).catchError(
//        (error) => print('(1)Error occured during division: $error'));
    var result = await divide(1, 0);
    print('(1) 1 / 0 = $result');
  } catch (ex) {
    print('(1.1)Error occured during division: ${ex.toString()}');
  }
}

// async error handling catches async exceptions
void main2() {
  divideFullAsync(1, 0)
      .then((result) => print('(2) 1 / 0 = $result'))
      .catchError(
          (error) => print('(2) Error occured during division: $error'));
}

// async/await allows to use try/catch for async exceptions
main3() async {
  try {
    await divideFullAsync(1, 0);
    print('3');
  } catch (error) {
    print('(3) Error occured during division: $error');
  }
}

main4() async {
//  try {
//    await divideFullAsyncNested();
//  } on Exception catch (e) {
//    print("(4) ${e.toString().replaceAll('Exception:', '').trimLeft().trimRight()}");
//  }
  try {
    divideFullAsyncNested()
        .then((v) => print(v))
        .catchError((err) => print(Constants.refinedExceptionMessage(err)));
  } on Exception catch (e) {
    print("(4) ${Constants.refinedExceptionMessage(e)}");
  }
}
like image 2
Mitch Avatar answered Nov 09 '22 10:11

Mitch