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?
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.
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)}");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With