How to catch DatabaseError in Flutter Firebase App - firebase

I am learning Flutter and I want to catch the exception that should be thrown ( as security rule is correctly rejecting it) at the Flutter Application/device.
Below is the code
try {
FirebaseDatabase.instance.reference().once().then((DataSnapshot snapshot) {
try {
debugPrint(snapshot.toString());
}
on DatabaseError catch (eIn1) {
debugPrint(' onRoot ' + eIn1.toString());
}
});
}on DatabaseError catch (eOut1) {
debugPrint(' on1 ' + eOut1.toString());
}
try {
FirebaseDatabase.instance.reference().child("todo").once().then((DataSnapshot snapshot) {
try {
debugPrint(snapshot.toString());
}
on DatabaseError catch (eIn2) {
debugPrint(' onNode ' + eIn2.toString());
}
});
}on Exception catch (eOut2) {
debugPrint(' on2 ' + eOut2.toString());
}
But the Exception is never thrown or catch by the Android Studio, In logCat I can see the exception,
com.example.flutterlogindemo E/flutter:
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception:
DatabaseError(-3, Permission denied, )
#0 Query.once (package:firebase_database/src/query.dart:84:41)
#1 _HomePageState.initState (package:flutter_login_demo/pages/home_page.dart:48:65)
but could not find a away to catch it in code and then act on the exception.

You can use the catchError to be able to catch the error:
FirebaseDatabase.instance.reference().child("todo").once().then((DataSnapshot snapshot) {
print(snapshot);
})
.catchError((error) {
print("Something went wrong: ${error.message}");
});
https://api.flutter.dev/flutter/package-async_async/DelegatingFuture/catchError.html

Repeating my answer to Flutter: PlatformException thrown by FireBase won't get caught here:
The try catch blocks will work if the Firebase call is within an async function and the await statement is used when calling Firebase.
For example, in the following code an error getting the token will be trapped by the on PlatformException catch (... block but an error writing the token to FB RTDB won't be:
Future<void> _saveDeviceToken() async {
try {
final _currentUser = _firebaseAuth.currentUser;
final fcmToken = await _firebaseMessaging.getToken();
if (fcmToken != null) {
// Save the token to Firebase - NO AWAIT STATEMENT
globals.firebaseDatabase
.reference()
.child("pushTokens")
.child("${_currentUser.uid}")
.set({"token": fcmToken});
}
} on PlatformException catch (error, stackTrace) {
print("error: $error");
}
}
whereas adding the await statement, as in the following code, will trap errors in writing to FB RTDB as well:
Future<void> _saveDeviceToken() async {
try {
final _currentUser = _firebaseAuth.currentUser;
final fcmToken = await _firebaseMessaging.getToken();
if (fcmToken != null) {
// Save the token to Firebase - AWAIT STATEMENT ADDED
await globals.firebaseDatabase
.reference()
.child("pushTokens")
.child("${_currentUser.uid}")
.set({"token": fcmToken});
}
} on PlatformException catch (error, stackTrace) {
print("error: $error");
}
}
If you don't want to or can't use await then, as per Peter's answer, the solution is to use the catchError statement instead of try catch.

Related

Flutter User creation and Signing in

Here is my code
I am trying to run this code with no avail.
import 'package:firebase_auth/firebase_auth.dart';
class AuthClass {
FirebaseAuth auth = FirebaseAuth.instance;
//create account
Future<String> createAccount(
{required String email, required String password}) async {
try {
await auth.createUserWithEmailAndPassword(
email: email, password: password);
return "Account created";
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
return 'The password provided is too weak.';
} else if (e.code == 'email-already-in-use') {
return 'The account already exists for that email.';
}
} catch (e) {
return 'Error Occured';
}
}
//sign in user
Future<String> signIn(
{required String email, required String password}) async {
try {
await auth.signInWithEmailAndPassword(email: email, password: password);
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
return 'No user found for that email.';
} else if (e.code == 'wrong-password') {
return 'Wrong password provided for that user.';
}
}
}
// reset password
Future<String> resetPassword({
required String email,
}) async {
try {
await auth.sendPasswordResetEmail(
email: email,
);
return 'Email Sent';
} catch (e) {
return 'Error Occured';
}
}
//sign out
void signOut() {
auth.signOut();
}
}
I need some help I am getting this error,
The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type.
Try adding either a return or a throw statement at the end.
Future signIn(...) "signIn"
Future createAccount(...) "createAccount"
is where i am getting the error
try on catch blocks work like this.
try executes code. If that fails, it throws an Exception.
Now, that Exception can be of many types and using on and catch together we can catch a specific exception and get that value inside e.
But the on FirebaseAuthException catch (e), only catches Exceptions of type FirebaseAuthException.
So, in a case where your try block throws something else, maybe NumberException, then it won't be caught.
For catching all other types of Exceptions, you need to add another catch block.
Like this,
try {
await auth.signInWithEmailAndPassword(email: email, password: password);
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
return 'No user found for that email.';
} else if (e.code == 'wrong-password') {
return 'Wrong password provided for that user.';
}
} catch (e) {
return 'Unknown Error.'; // Change this to whatever you want.
}
Think of the try like an if block. Then your on FirebaseAuthException catch (e) would be an if else block. But you also need to handle the else block and that is your catch (e).
Hope it makes sense.

how to get Firebase Firestore exception code on Flutter?

from the documentation in here it seems that Firestore have some error codes. how to catch that in Flutter so I can localize the error message
I have tried to use the code below
Future<User?> getUser({required String userID}) async {
try {
final documentSnapshot = await _db.collection(path).doc(userID).get();
if (documentSnapshot.exists) {
return User.fromFirestore(documentSnapshot.data()!);
} else {
return null;
}
} on FirebaseFirestoreException (error) {
print(error.code);
// I hope I can get the error.code in here
}
}
but I have error
_db.collection(path).doc(userID).get()
.then((e){
User user = User.fromFirestore(e.data()!);
}).catchError((err)=> print(err.message));

Flutter - try and catch dont't handle firebase_auth errors

I have a problem handling firebase_auth errors, every way when I try signIn, I get some errors,
although I have used try and catch.
Earlier I have turned off the uncaught exceptions option in vsc but I would like to also get the error message from catch
sample errors message
Future<Either<LoginFailure, LoginSucces>> signInWithEmail(
{String email, String password}) async {
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} on PlatformException catch (e) {
return Left(LoginFailure(errorMessage: '${e.toString()}'));
}
}
In your log, you see the type of the uncaught exception is PlatformException, but it is not the type of the original exception throwed by signInWithEmailAndPassword(); it is instead used by the flutter framework, when it intercept the exception1, to wrap it. So if you want to catch only the exceptions thrown by signInWithEmailAndPassword(), check their exact type first, consulting the doc (if it explicit) or with a try/catch without on clause, like the following:
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} catch (e, stack) {
print("Catched exception: $e");
//if the exception log not shows the type (it is rare), you can log the exact type with:
print(e.runtimeType);
}
When you know the correct type of the exceptions that you want to catch, then you use the on clause:
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} on FirebaseError catch (e, stack) {
print(e);
//exceptions with a type other than FirebaseError are not caught here
}
Note FirebaseError is the type thrown using my package, firebase (others exist too, like firebase_auth); if you use a different package, check for yourself which exceptions you need to catch.
1 Flutter has its own mechanism for catching exceptions, which are therefore not really 'uncaught'; see for example this doc on error in flutter)
This code only catch PlatformException as written.
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} on PlatformException catch (e) {
return Left(LoginFailure(errorMessage: '${e.toString()}'));
}
you can catch all exception like this.
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} catch (e) {
return Left(LoginFailure(errorMessage: '${e.toString()}'));
}
also you can do this
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} on PlatformException catch (e) {
return Left(LoginFailure(errorMessage: '${e.toString()}'));
} catch(e) {
// All other than Platform exception will drop here
print(e);
}

Flutter: PlatformException thrown by FireBase won't get caught

I have a function that is used to sign in to Firebase using firebase_auth, however, whenever an exception is thrown it isn't getting caught and still appears in the Android Studio console nor do the print statements in the catch block ever run.
How do I fix this?
signIn({String email, String password}) {
print('listened');
try {
FirebaseAuth.instance.signInWithEmailAndPassword(
email: email, password: password);
}
on PlatformException catch (signUpError) {
print(signUpError.code);
if (signUpError.code == 'ERROR_WEAK_PASSWORD') {
print('Weak Password');
}else if(signUpError.code=='ERROR_USER_NOT_FOUND'){
print('Invalid Username');
}
else{
print(signUpError.toString());
}
}
}
signInWithEmailAndPassword returns a Future<AuthResult> (it is asynchronous), therefore you need to use the catchError method to catch the error when calling an asynchronous method:
FirebaseAuth.instance.signInWithEmailAndPassword(email: email, password: password).then((result) {
print(result);
})
.catchError((error) {
print("Something went wrong: ${error.message}");
});
Check the following:
https://api.dart.dev/stable/2.3.0/dart-async/Future/catchError.html
https://medium.com/firebase-tips-tricks/how-to-use-firebase-authentication-in-flutter-50e8b81cb29f
The try catch blocks will work if the Firebase call is within an async function and the await statement is used when calling Firebase.
For example, in the following code an error getting the token will be trapped by the on PlatformException catch (... block but an error writing the token to FB RTDB won't be:
Future<void> _saveDeviceToken() async {
try {
final _currentUser = _firebaseAuth.currentUser;
final fcmToken = await _firebaseMessaging.getToken();
if (fcmToken != null) {
// Save the token to Firebase - NO AWAIT STATEMENT
globals.firebaseDatabase
.reference()
.child("pushTokens")
.child("${_currentUser.uid}")
.set({"token": fcmToken});
}
} on PlatformException catch (error, stackTrace) {
print("error: $error");
}
}
whereas adding the await statement, as in the following code, will trap errors in writing to FB RTDB as well:
Future<void> _saveDeviceToken() async {
try {
final _currentUser = _firebaseAuth.currentUser;
final fcmToken = await _firebaseMessaging.getToken();
if (fcmToken != null) {
// Save the token to Firebase - AWAIT STATEMENT ADDED
await globals.firebaseDatabase
.reference()
.child("pushTokens")
.child("${_currentUser.uid}")
.set({"token": fcmToken});
}
} on PlatformException catch (error, stackTrace) {
print("error: $error");
}
}
If you don't want to or can't use await then, as per Peter's answer, the solution is to use the catchError statement instead of try catch.

How do I tell the difference between exceptions in flutter authenticating with Firebase?

I have Firebase a sign in for my app. I want to report exceptions to the user so he can correctly login. It is email and password sign in signInWithEmailAndPassword(_email, _password). Testing I can create two exceptions which are self explanatory
1/ Error: PlatformException(exception, There is no user record corresponding to this identifier. The user may have been deleted., null)
2/ Error: PlatformException(exception, The password is invalid or the user does not have a password., null)
I'm using a try catch block to catch the error. Here is my code:
void validateAndSubmit() async {
FocusScope.of(context).requestFocus(new FocusNode());
if (validateAndSave()) {
try {
var auth = AuthProvider.of(context).auth;
FirebaseUser user =
await auth.signInWithEmailAndPassword(_email, _password);
print('Signed in: ${user.uid}');
Navigator.pop(context);
widget.loginCallback(user);
} catch (e) {
print('Error: $e');
setState(() {
_showMessage=true;
});
}
}
}
I want to give a different message depending on the exception. But there doesn't seem to be any code associated with the exception.
You can catch different kind of exceptions, for each exceptions, you can check the code
void validateAndSubmit() async {
FocusScope.of(context).requestFocus(new FocusNode());
if (validateAndSave()) {
try {
var auth = AuthProvider.of(context).auth;
FirebaseUser user =
await auth.signInWithEmailAndPassword(_email, _password);
print('Signed in: ${user.uid}');
Navigator.pop(context);
widget.loginCallback(user);
} on FirebaseAuthInvalidUserException catch (e) {
print('FirebaseAuthInvalidUserException: $e');
if (e.code === 'ERROR_USER_NOT_FOUND') {
setState(() {
_showMessage=true;
});
} else {
// do something
}
}
} on FirebaseAuthInvalidCredentialsException catch (e) {
// do something InvalidCredentials
} catch (e) {
// do something else
}
}
You can check e.code.
Check out native firebase documentation. It has values like 'ERROR_USER_NOT_FOUND'

Resources