I'm having a weird issue here. Simple code:
router.post("/resetpassword/:email", async (req, res) => {
try {
var auth = firebase.auth();
await auth.sendPasswordResetEmail(req.params.email);
res.sendStatus(200);
} catch (e) {
console.log(e);
res.sendStatus(400);
}
});
This code works fine if
But if the email is malformatted, I also get an exception with status code, but then my Express application crashes after having invoked the catch block. The HTTP 400 is sent to the client, but after that, my app is dead.
Here's the console output. The first block if for an unknown email address, the second for a malformatted one.
{ [Error: There is no user record corresponding to this identifier. The user may have been deleted.]
code: 'auth/user-not-found',
message: 'There is no user record corresponding to this identifier. The user may have been deleted.' }
{ [Error: The email address is badly formatted.]
code: 'auth/invalid-email',
message: 'The email address is badly formatted.' }
[...]\node_modules\firebase\auth-node.js:39
h.send=function(a){if(a)if("string"==typeof a)this.sa.send(a);else throw Error("Only string data is supported");else this.sa.send()};h.abort=function(){this.sa.abort()};h.setRequestHeader=function(){};h.He=function(){this.status=200;this.responseText=this.sa.responseText;Ic(this,4)};h.Jd=function(){this.status=500;this.responseText="";Ic(this,4)};h.Je=function(){this.Jd()};h.Ie=function(){this.status=200;Ic(this,1)};var Ic=function(a,b){a.readyState=b;if(a.onreadystatechange)a.onreadystatechange()};var Jc=function(a,b,c){this.Ue=c;this.we=a;this.kf=b;this.oc=0;this.gc=null};Jc.prototype.get=function(){var a;0<this.oc?(this.oc--,a=this.gc,this.gc=a.next,a.next=null):a=this.we();return a};Jc.prototype.put=function(a){this.kf(a);this.oc<this.Ue&&(this.oc++,a.next=this.gc,this.gc=a)};var Kc=function(a){l.setTimeout(function(){throw a;},0)},Lc,Mc=function(){var a=l.MessageChannel;"undefined"===typeof a&&"undefined"!==ty
Error: The email address is badly formatted.
[nodemon] app crashed - waiting for file changes before starting...
I currently assume this is a stupid mistake from my side (I'm fairly new to node/Express). Any idea what I am missing here?
I came across this error myself while working with firebase.auth() myself, and is very peculiar indeed. What I figured is that firebase.auth() seems to use it's own Promise variant, and it is going to crash your app if that promise does not catch the error, or even throw the error in the .then/.catch chained to it.
here is a small function I made that makes sure it turns the rejected promise into a resolved promise, before again turning it into a rejected promise. This prevented my app from crashing, but I couldn't find an easier way.
let firebase_auth_wrap = async (promise) => {
let rejected = Symbol();
let value_or_error = await promise.catch((error) => {
return { [rejected]: true, error: error };
});
if (value_or_error[rejected]) {
throw value_or_error.error;
} else {
return value_or_error;
}
}
...
let { uid } = await firebase_auth_wrap(firebase.auth().signInWithEmailAndPassword(email, password));
Hope it works for you too, and let me know if it could be done more intuitively :)
When you run this:
await auth.sendPasswordResetEmail(req.params.email);
inside of a try/catch block then you handle two things:
auth.sendPasswordResetEmail() throwing an exception immediatelyauth.sendPasswordResetEmail() rejecting the returned promiseWhat you don't handle is when in some other part of your code something happens and thrown an exception that is not caught by anything.
Of course it's impossible to tell you where it happened in your case when you post an example of an error message pointing to a line with thousands of characters but here is a simple example.
In this example you will catch the rejected promise:
let f = () => new Promise((res, rej) => {
rej(new Error('Error'));
});
(async () => {
try {
let x = await f();
console.log('Returned value:', x);
} catch (e) {
console.log('Handled error:', e.message);
}
})();
In this example you will catch the thrown exception:
let f = () => new Promise((res, rej) => {
throw new Error('Error');
});
(async () => {
try {
let x = await f();
console.log('Returned value:', x);
} catch (e) {
console.log('Handled error:', e.message);
}
})();
In this example you will handle the rejection that happened in a different tick of the event loop:
let f = () => new Promise((res, rej) => {
setImmediate(() => rej(new Error('Error')));
});
(async () => {
try {
let x = await f();
console.log('Returned value:', x);
} catch (e) {
console.log('Handled error:', e.message);
}
})();
But in this example you will not handle the exception thrown on a different tick of the event loop:
let f = () => new Promise((res, rej) => {
setImmediate(() => { throw new Error('Error'); });
});
(async () => {
try {
let x = await f();
console.log('Returned value:', x);
} catch (e) {
console.log('Handled error:', e.message);
}
})();
Something like that must be happening in your case.