I'm getting the error below. My problem is NOT with the actual error but the fact that it is saying that the error was Uncaught. If you take a look at my auth.service.ts
and sign-inponent.ts
files I am catching the error.
My question is, why am getting the Error: Uncaught (in promise) error in the console? What am I missing?
I'm using
"@angular/fire": "^7.0.4"
"firebase": "^9.0.2"
"rxjs": "6.6.7"
auth.service.ts
/**
* Sign in
*
* @param credentials
*/
signIn(credentials: { email: string; password: string }): Promise<any>
{
return this.auth.signInWithEmailAndPassword(credentials.email, credentials.password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
//console.log(user);
// Store the access token in the local storage
userCredential.user.getIdToken().then(token => {
this.accessToken = token;
//console.log(token);
})
// Set the authenticated flag to true
this._authenticated = true;
// Store the user on the user service
//this._userService.user = user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log('Show Error', error.code);
throw errorCode;
});
}
sign-inponent.ts
/**
* Sign in
*/
signIn(): void
{
// Return if the form is invalid
if ( this.signInForm.invalid )
{
return;
}
// Disable the form
this.signInForm.disable();
// Hide the alert
this.showAlert = false;
// Sign in
this._authService.signIn(this.signInForm.value)
.then(
() => {
// Set the redirect url.
// The '/signed-in-redirect' is a dummy url to catch the request and redirect the user
// to the correct page after a successful sign in. This way, that url can be set via
// routing file and we don't have to touch here.
const redirectURL = this._activatedRoute.snapshot.queryParamMap.get('redirectURL') || '/signed-in-redirect';
// Navigate to the redirect url
this._router.navigateByUrl(redirectURL);
},
(response) => {
console.log('error from auth.service', response);
// Re-enable the form
this.signInForm.enable();
// Reset the form
this.signInNgForm.resetForm();
// Set the alert
this.alert = {
type : 'error',
message: 'Wrong email or password'
};
// Show the alert
this.showAlert = true;
}
);
}
I'm getting the error below. My problem is NOT with the actual error but the fact that it is saying that the error was Uncaught. If you take a look at my auth.service.ts
and sign-in.ponent.ts
files I am catching the error.
My question is, why am getting the Error: Uncaught (in promise) error in the console? What am I missing?
I'm using
"@angular/fire": "^7.0.4"
"firebase": "^9.0.2"
"rxjs": "6.6.7"
auth.service.ts
/**
* Sign in
*
* @param credentials
*/
signIn(credentials: { email: string; password: string }): Promise<any>
{
return this.auth.signInWithEmailAndPassword(credentials.email, credentials.password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
//console.log(user);
// Store the access token in the local storage
userCredential.user.getIdToken().then(token => {
this.accessToken = token;
//console.log(token);
})
// Set the authenticated flag to true
this._authenticated = true;
// Store the user on the user service
//this._userService.user = user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log('Show Error', error.code);
throw errorCode;
});
}
sign-in.ponent.ts
/**
* Sign in
*/
signIn(): void
{
// Return if the form is invalid
if ( this.signInForm.invalid )
{
return;
}
// Disable the form
this.signInForm.disable();
// Hide the alert
this.showAlert = false;
// Sign in
this._authService.signIn(this.signInForm.value)
.then(
() => {
// Set the redirect url.
// The '/signed-in-redirect' is a dummy url to catch the request and redirect the user
// to the correct page after a successful sign in. This way, that url can be set via
// routing file and we don't have to touch here.
const redirectURL = this._activatedRoute.snapshot.queryParamMap.get('redirectURL') || '/signed-in-redirect';
// Navigate to the redirect url
this._router.navigateByUrl(redirectURL);
},
(response) => {
console.log('error from auth.service', response);
// Re-enable the form
this.signInForm.enable();
// Reset the form
this.signInNgForm.resetForm();
// Set the alert
this.alert = {
type : 'error',
message: 'Wrong email or password'
};
// Show the alert
this.showAlert = true;
}
);
}
Share
Improve this question
edited Sep 21, 2021 at 14:50
Frank van Puffelen
600k85 gold badges890 silver badges860 bronze badges
Recognized by Google Cloud Collective
asked Sep 21, 2021 at 14:33
Luis CabreraLuis Cabrera
5691 gold badge7 silver badges18 bronze badges
5
-
2
You're rethrowing the error again
throw errorCode;
, and I don't see code that handles that rethrow at first glance. – Frank van Puffelen Commented Sep 21, 2021 at 14:51 - Pardon my ignorance but how can I fix it? – Luis Cabrera Commented Sep 21, 2021 at 15:08
- Not rethrowing it would be one option. The other would be to catch the rethrown error higher in the callstack, and handle it there without rethrowing it. – Frank van Puffelen Commented Sep 21, 2021 at 15:12
-
I removed the rethrowing and the error is not being returned to the
sign-in.ponent.ts
. The console still shows the firebase error. – Luis Cabrera Commented Sep 21, 2021 at 15:17 - Could you show me in code how to handle please? I would greatly appreciate it – Luis Cabrera Commented Sep 21, 2021 at 15:20
3 Answers
Reset to default 5 +50First of all, my native language is not English, so if I write like a fool you know why.
try this:
_authService.service.ts
import { getAuth, signInWithEmailAndPassword, Auth, inMemoryPersistence, browserLocalPersistence } from '@angular/fire/auth';
constructor(private _fireAuth: Auth,) {
/**
* Sign-in
*
* @param credentials
* @param rememberMe
*/
async signIn(credentials: { email: string; password: string }, rememberMe: boolean): Promise<any> {
// firebase Persistence.LOCAL browserLocalPersistence
// firebase Persistence.SESSION browserSessionPersistence
// firebase Persistence.NONE inMemoryPersistence
return new Promise(async (resolve, reject) => {
//Initialize auth()
const auth = getAuth();
// Extra function
if (rememberMe) {
await getAuth().setPersistence(browserLocalPersistence).catch(error => reject(-1));
} else {
await getAuth().setPersistence(inMemoryPersistence).catch(error => reject(-1));
}
signInWithEmailAndPassword(auth, credentials.email, credentials.password).then(async (userCredential) => {
// Signed in
const user = userCredential.user;
console.log(user);
// Store the access token in the local storage
await userCredential.user.getIdTokenResult().then(token => {
this.accessToken = token.token;
console.log(token);
})
// Set the authenticated flag to true
this._authenticated = true;
}).catch(error => reject(error.code));
});
}
Note: As you can see I have added some extra functions that you can remove if you are not interested (setPersistence), this allows you to take into account the user's choice to stay logged in if he wants to, or to remove his login when he closes the tab.
sign-in.ponent.ts
alert = {
userNotFound : false,
wrongPassword: false,
unknownError : false,
};
/**
* Sign in
*/
signIn(): void
{
// Return if the form is invalid
if ( this.signInForm.invalid )
{
return;
}
// Disable the form
this.signInForm.disable();
// Hide the alert
this.showAlert = false;
// Sign in
this._authService.signIn(this.signInForm.value)
.then(
() => {
// Set the redirect url.
// The '/signed-in-redirect' is a dummy url to catch the request and redirect the user
// to the correct page after a successful sign in. This way, that url can be set via
// routing file and we don't have to touch here.
const redirectURL = this._activatedRoute.snapshot.queryParamMap.get('redirectURL') || '/signed-in-redirect';
// Navigate to the redirect url
this._router.navigateByUrl(redirectURL);
},
(response) => {
console.log('error from auth.service', response);
// Re-enable the form
this.signInForm.enable();
// Reset the form
this.signInNgForm.resetForm();
// Set the alert
if (error === - 1) {
this.alert.unknownError = true;
} else if (error === 'auth/email-not-found' || error === 'auth/user-not-found') {
this.alert.userNotFound = true;
} else if (error === 'auth/wrong-password') {
this.alert.wrongPassword = true;
}
}
);
}
For me, explicitly catch
ing the error as in the above answers still resulted in the error being sent to the console as Uncaught (in Promise)
. For whatever reason, in addition to sending the error to be caught via Promise.catch
, Angular was routing the error through its default ErrorHandler and claiming that the error was uncaught. I had to override the default ErrorHandler with my own, detect that these were FirebaseErrors and then ignore them (since I already had an explicit Promise.catch
defined where I needed it).
Some tips in case they are helpful:
- Angular only recognizes error handlers defined on the root module. Definitions on child modules seem to be ignored. You get one global error handler that needs to do everything.
- The core FirebaseErrors seem to be stored in a
rejection
property on the mainerror
object. You can detect them like so:
import { ErrorHandler, Injectable } from "@angular/core";
import { FirebaseError } from "firebase/app";
interface AngularFireError extends Error {
rejection: FirebaseError;
}
function errorIsAngularFireError(err: any): err is AngularFireError {
return err.rejection && err.rejection.name === 'FirebaseError';
}
// Not providedIn 'root': needs special handling in app.module to override default error handler.
@Injectable()
export class YourErrorHandler implements ErrorHandler {
handleError(error: any) {
// AngularFire errors should be catchable and handled in ponents; no need to further process them.
if (!errorIsAngularFireError(error)) {
console.error(error);
}
}
}
And in your root module:
providers: [
...,
{ provide: ErrorHandler, useClass: YourErrorHandler }
],
as Frank mentionned you are throwing an error without catching it back at a higher lever what I would try would be to do as so:
try {
this._authService.signIn(this.signInForm.value)
.then(
() => {
// Set the redirect url.
// The '/signed-in-redirect' is a dummy url to catch the request and redirect the user
// to the correct page after a successful sign in. This way, that url can be set via
// routing file and we don't have to touch here.
const redirectURL = this._activatedRoute.snapshot.queryParamMap.get('redirectURL') || '/signed-in-redirect';
// Navigate to the redirect url
this._router.navigateByUrl(redirectURL);
},
(response) => {
console.log('error from auth.service', response);
// Re-enable the form
this.signInForm.enable();
// Reset the form
this.signInNgForm.resetForm();
// Set the alert
this.alert = {
type : 'error',
message: 'Wrong email or password'
};
// Show the alert
this.showAlert = true;
}
);
} catch(e) {}
just surround your code with a try catch
block so the error is muted. I didn't tested it but maybe calling another catch
method after then
could do the trick still it would be at the same level (Promise level) so I'm not sure it would work.