NodeJS Error Handling - Throwing error promise to try catch - node.js

im trying to get the promise error, and throw to the "try catch" to concentrate the return of the error in one place.
like this:
async schedule(req, res) {
try {
//here is the function that returns a promise
service.search()
.then(async data => {
if (data.length > 0) {
res.status(200).json("OK!");
}
})
.catch(async error => {
//here i want to throw this error to the "try catch" to return the error message
throw new Error(error);
})
}
catch (error) {
res.status(400).json(error);
};
}
but when goes to "throw new Error(error);" gives me the message:
(node:15720) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
warning.js:27
someone could help me to understand what im doing wrong?
thank so much!
Rafael
UPDATE
based on the Marcos answer, i did:
async schedule(req, res) {
try {
const data = await service.search();
if (data.length > 0) {
res.status(200).json("OK!");
}
}
catch (error) {
res.status(400).json(error);
};
}
and worked... Now i understand how to handle this errors... thanks!

You either use async/await with a try/catch or .then/.catch, you don't mix both ways.
async schedule(req, res) {
try {
//here is the function that returns a promise
// If service.search rejects, it will go to the `catch`
const data = await service.search()
if (data.length > 0) {
return res.status(200).json("OK!");
}
// do something here
// res.status(400).send('Invalid data')
// throw new Error('Invalid data')
} catch (error) {
res.status(400).json(error);
}
}
or
schedule(req, res) {
service.search()
.then(data => {
if (data.length > 0) {
res.status(200).json("OK!");
}
})
.catch(error => {
res.status(400).json(error);
})
}

Related

(node:5151) UnhandledPromiseRejectionWarning

I have the following async function that successfully runs on every result returned by the "Quote.insertMany" mongoose method. However, once I run the function I get a "SAVED" output for each one followed by the following error for each one of them:
SAVED
SAVED
...
SAVED
(node:5151) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:5151) UnhandledPromiseRejectionWarning: MongoError: Cannot use a session that has ended
...
Closing connection
What's wrong with the function below? i.e. how can I handle these rejections:
(async function(){
db.connect();
await Quote.insertMany(quotes).
then(results => {
return Promise.all((results).map(function(quote) {
return Author.findOne({id: quote.authorid}, function(err, author){
if (err){
return next(err);
}
if(author != null){
try{
author.quotes.push(quote._id);
author.save();
console.log("SAVED");
}
catch(e){
return next(e);
}
}
})
}))
}).
catch(e => {
console.log(e);
});
console.log("Closing connection");
db.close();
})();
This was simple. I didn't realize "save()" was returning a promise.
Fix:
author.save().then().catch(e => {
console.log(e);
});

Async/Await & UnhandlePromiseRejectWarning [duplicate]

This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 3 years ago.
I have the following code writed in nodejs express and firebase
route.js
try{
const test = await invoiceData.setAssignsInvoiced();
res.json({
status: true,
message: "Successful Invoice Generation"
});
}catch (e) {
res.status(500).json({
status: false,
message: "Internal Server Error",
data: e
});
}
InvoicesStorage.js
setAssignsInvoiced = async() => {
return new Promise(async (resolve,reject)=>{
try {
await _getAssignsForInvoiced(this);
this.assignsForInvoiced.forEach(async assing => {
let aux = assing._key.path.segments.length;
let ref = assing._key.path.segments[aux - 1];
await _updateAssignsToInvoiced(assing.data(),ref);
});
resolve(true)
} catch (error) {
console.error(error)
reject(error)
}
})
};
const _updateAssignsToInvoiced = async (assing, ref) => {
try {
const { invoiceNum } = assing.data(); //Here's an intentional error
await db
.collection("leadAsign")
.doc(ref)
.update({
invoiced: true,
updateDate: Date.now() - 240 * 60 * 1000,
invoiceNum
});
} catch (error) {
console.error(error);
throw new Error("Error at update to invoiced assigns");
}
};
How I hope it works:
According to me, I should throw out a synchronous error because my code has "await" and stop the system.
The answer I have:
the code runs asynchronously, that is, after calling the function the "await" has no effect and answers a "res.json" with status 200 and it is only after it throws the next error.
TypeError: assing.data is not a function
at _updateAssignsToInvoiced (D:\$Workzone\gd_fridays_h\src\controllers\invoices\InvoicesStorage.js:90:35)
at D:\$Workzone\gd_fridays_h\src\controllers\invoices\InvoicesStorage.js:55:23
at Array.forEach (<anonymous>)
at D:\$Workzone\gd_fridays_h\src\controllers\invoices\InvoicesStorage.js:51:37
true
POST /generateSingle 200 5182.650 ms - 57
(node:5600) UnhandledPromiseRejectionWarning: Error: Error at update to invoiced assigns
at _updateAssignsToInvoiced (D:\$Workzone\gd_fridays_h\src\controllers\invoices\InvoicesStorage.js:102:11)
at D:\$Workzone\gd_fridays_h\src\controllers\invoices\InvoicesStorage.js:55:23
at Array.forEach (<anonymous>)
at D:\$Workzone\gd_fridays_h\src\controllers\invoices\InvoicesStorage.js:51:37
(node:5600) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 4)
(node:5600) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
async/await doesn't work as you're expecting it to inside a forEach loop. An abundance of info on that specific issue here: https://stackoverflow.com/a/37576787/4043746
To fix your problem, you could use a for/of loop:
setAssignsInvoiced = async () => {
return new Promise(async (resolve, reject) => {
try {
await _getAssignsForInvoiced(this)
for (const assign of this.assignsForInvoiced) {
let aux = assign._key.path.segments.length
let ref = assign._key.path.segments[aux - 1]
await _updateAssignsToInvoiced(assign.data(), ref)
}
resolve(true)
} catch (error) {
console.error(error)
reject(error)
}
})
}
However, I'd also be tempted to suggest not returning a promise, as you're essentially doing that due to it being an async function. Something like this should work and is cleaner imo:
setAssignsInvoiced = async () => {
try {
await _getAssignsForInvoiced(this)
for (const assign of this.assignsForInvoiced) {
let aux = assign._key.path.segments.length
let ref = assign._key.path.segments[aux - 1]
await _updateAssignsToInvoiced(assign.data(), ref)
}
} catch (error) {
console.error(error)
// Re-throwing the error to pass the error down, just like you've
// done inside your _updateAssignsToInvoiced function's catch
throw new Error('Error setting assigns')
}
}
Async/await inside a forEach() loop will not wait until all the async operations inside the loop is completed.
One approach would be using Promise.all() like so:
const setAssignsInvoiced = async () => {
try {
await _getAssignsForInvoiced(this);
await _updateAssignsList(this.assignsForInvoiced);
return true;
} catch (error) {
console.error(error);
return new Error(error);
}
};
const _updateAssignsList = assignsList => {
return Promise.all(
assignsList.map(async assign => {
let aux = assign._key.path.segments.length;
let ref = assign._key.path.segments[aux - 1];
return await _updateAssignsToInvoiced(assign.data(), ref);
})
);
};
I've just extracted the async loop process to a separate function which return a Promise.

Unhandle rejection promise async await chain

I'm fairly new to async await in javascript so this question might be something I don't know.
I have this
async function foo(req, res, next) {
try {
await scan(req.params.stack);
res.send('ok');
} catch (err) {
res.status(500).send('fail');
}
}
async function scan(stack) {
try {
const libs = [1,2,3];
const promises = libs.map(async l => analyze(stack, l)
.catch((err) => { throw new Error(err); }));
return q.allSettled(promises)
.then((results) => {
const rejected = results.filter(r => r.state === 'rejected');
if (rejected.length === results.length) throw new Error('Failed');
return results;
})
.catch((err) => {
throw new Error(err);
});
} catch (err) {
throw new Error(err);
}
}
async function analyze(stack, libraries) {
try {
const config = await buildConfiguration(stack, libraries);
return await databaseInsertion(vulnsObject);
} catch (err) {
return Promise.reject('Error while trying to analyze libs');
}
}
Somehow I'm getting this wild warning and I don't know where I am not catching the error.
Of course, I'm making build configuration fail in order to test the error, but instead of having a normal flow cathing the error I got this:
(node:415) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: Error while trying to analyze libs
Am I using async await good? Is there any pattern I should follow in order to chain async await?
The wild thing is that the foo function works well, meaning that the res.status.(500).send('fail'); works and I'm getting the response
When I was using native promises this error didn't appear.
I'm really stuck here
While using async-await scan function you were mixing .then() .catch() waterfall with await. async-await handles promises as good as .then(). So stick with one flow and try to mix both in one function or one inside another.
async foo(req, res, next) {
try {
await scan(req.params.stack);
res.send('ok');
} catch (err) {
res.status(500).send('fail');
}
}
async scan(stack) {
try {
const libs = [1,2,3];
// This libs.map functions return promise. then why not use await?
const promises = await libs.map(async l => analyze(stack, l);
// Again q.allSettled returns promise, use await here too
let results = await q.allSettled(promises);
const rejected = results.filter(r => r.state === 'rejected');
if (rejected.length === results.length) throw new Error('Failed');
return results;
}
// If any promise call reject function will be in catch
catch (err) {
throw new Error(err);
}
}
async function analyze(stack, libraries) {
try {
const config = await buildConfiguration(stack, libraries);
return await databaseInsertion(vulnsObject);
}
catch (err) {
console.log(err);
return null;
}
}
Calling an async function (here, analyze) would return a promise, which will resolve or reject according to the return value of the async function or whether an error was thrown.
Now, the analyze function is handling the error thrown but it will return a Promise.reject() when an error is thrown. A Promise.reject() is the unhandled rejection here, which is what the log is stating.
In terms of a synchronous function the equivalent will be
function sync() {
try {
// do something dangerous
} catch (ex) {
throw Error('Something bad happened'); // this error is still being thrown and nobody is handling it
}
}
To handle this error you can do the following when you are calling sync, wrap it in try and catch again
try {
sync();
} catch (ex) {
console.error(ex); // not gonna throw another exception, otherwise the program might crash
}
Now, the equivalent of this wrap for the analyze function will be using another async function, or better since calling async function will return a Promise, use the catch method of a Promise
analyze()
.then(() => console.log('My work is done here'))
.catch(ex => console.error(ex)); // NOTE: not throwing another exception
Even better would be to not return a rejection from catch in the first place, thus making analyze,
async function analyze(stack, libraries) {
try {
const config = await buildConfiguration(stack, libraries);
return await databaseInsertion(vulnsObject);
} catch (err) {
console.error(err); // not eating up good errors with something vague is always good
return null; // or something else to signify that insert failed
}
}
In the analyze() you are returning Project.reject() but analyze() is an async function. Therefor it resolves any value that you return and rejects any error you throw.
async function analyze(stack, libraries) {
try {
const config = await buildConfiguration(stack, libraries);
return await databaseInsertion(vulnsObject);
} catch (err) {
return Promise.reject('Error while trying to analyze libs');
}
}
So when the analyze function catches an error you are creating a rejection but then resolving the function. So Promise.reject('Error while trying to analyze libs'); is not being handled. Since async functions always return a promise that resolves with whatever you return and rejects whatever you throw, your analyze function is always going to resolve. Try doin this...
async function analyze(stack, libraries) {
try {
const config = await buildConfiguration(stack, libraries);
return await databaseInsertion(vulnsObject);
} catch (err) {
throw Error('Error while trying to analyze libs');
}
}
The other thing I see as a possible problem in this code is even though you pass the map(async func) an async function, it doesn't care. It won't wait for each function to complete before calling the next.
const promises = libs.map(async l => analyze(stack, l)
.catch((err) => { throw new Error(err); }));
return q.allSettled(promises)
.then((results) => {
const rejected = results.filter(r => r.state === 'rejected');
if (rejected.length === results.length) throw new Error('Failed');
return results;
})
.catch((err) => {
throw new Error(err);
});
There are two changes bellow
const promises = libs.map(async l => await analyze(stack, l)
.catch((err) => { throw new Error(err); }));
return q.allSettled( await promises)
.then((results) => {
const rejected = results.filter(r => r.state === 'rejected');
if (rejected.length === results.length) throw new Error('Failed');
return results;
})
.catch((err) => {
throw new Error(err);
});
I added an await before the analyze function and an await before passing the promises variable into q.allSettled().

Async function throws error - yet express endpoint that calls it - does not see it

I have a helper function that hits an API and fetches a page by ID. It uses async/await and I am trying to handle errors with try catch.
To test the error handling I am purposefully giving it an ID that does not exist.
Here is the method:
const findPage = async (req, res, pageId) => {
let document
try {
let response = await getByID(pageId)
if (!response) throw Error('No Response')
return document
} catch (error) {
console.log(error) // I can see the error is being thrown.. I am purposefuly giving it an id that does not exist
return error
}
}
It does indeed throw an error like I expect. However, I am calling the function in another part of the app using an express Route.
Router.route('/page/:id').get(async (req, res) => {
let results
try {
results = await findPage(req, res, req.params.id) // This Function Returns an error
// Yet we still get results
res.json({results, msg: 'WHY?'})
} catch (error) {
res.send(error)
}
})
In the same Router file, I have attempted to add some specific middleware to this Router as well, but as there is no error, it is never triggered.
Router.use((err, req, res, next) => {
if (err) {
console.log('holy error')
} else {
console.log('no error')
}
next(err)
})
How can the express API call return results, and not the error, when the function it is calling itself returns an error?
What I can see from your code is that your try/catch block inside the Router.route is not catching an expetion of findPage function, and that is becasue you are also catching an exception inside that findPage and just simply returning an error rather than throwing an exception;
try {
results = await findPage(req, res, req.params.id) // This Function Returns an error
// Yet we still get results
res.json({results, msg: 'WHY?'})
} catch (error) {
res.send(error)
}
So inside findPage if you really need to do something when excptions happening then you have to catch it and if you like the calller also catch the expetion you need to throw the same erro or a new more context-aware error again. Otherwise if you dont do any action when exception happens you dont need to catch it.
const findPage = async (req, res, pageId) => {
let document
try {
let response = await getByID(pageId)
if (!response) throw Error('No Response')
return document
} catch (error) {
// do something here if you really need to otherwise you dont need to catch exceptions here
// then rather than `return error` you should
throw error
}
}
You are catching the error in findPage() which means the error won't propagate up the call stack. You are just returning the error like a normal value, which will end up in the variable results in your Routes function. If you want to deal with the error in both places you need to throw it again in findPage():
async function callee(){
try {
throw("Some Error")
} catch(err) {
console.log("caught error in callee:", err)
throw(err)
}
}
async function caller(){
try {
let val = await callee()
console.log("returned value", val)
} catch (err) {
console.log("caught error in caller: ", err)
}
}
caller()
If you don't want to deal with it on both places, catch it in the function that's responsible for handling errors:
async function callee(){
throw("Some Error")
}
async function caller(){
try {
let val = await callee()
console.log("returned value", val)
} catch (err) {
console.log("caught error in caller: ", err)
}
}
caller()

NodeJS: understanding promise

I am starting to use promise in NodeJS. The requirement is to use these because of async calls. Here is the first code I wrote for promise.
function asyncFunc(data) {
return new Promise(
function(resolve, reject) {
try {
resolve(data);
} catch (err) {
reject("Custom Error");
}
});
}
//Usage:
asyncFunc('Sample String')
.then(result => { console.log(result); })
.catch(error => { console.log(error); });
//Output:
Sample String
null
//If I change the code to:
function asyncFunc(data) {
return new Promise(
function(resolve, reject) {
try {
reject("Custom Error");
} catch (err) {
resolve("Data");
}
});
}
//Output:
//Exception has occurred: string
//I get the above exception at line: reject("Custom Error");
So the question is "reject" can only be used from "catch" block? Why can't I raise "reject" event manually? What is the scenario "reject" is used? Can someone provide me a better example where I can use both "resolve" and "reject"?
You can use reject if you want, of course.
Let's suppose you have a function that resolves a promise if a person is adult, and rejects it if not.
You'd have something like this:
function asyncFunc(age) {
return new Promise((resolve, reject) => {
if(age >= 18) {
resolve(true);
} else {
// here you call reject manually outside of a catch block
reject(false);
// or
// reject(Error('not adult'));
}
});
}
usage:
asyncFunc(19).then(result => {
console.log(result); // true
})
.catch(error => {
console.log(error); // false or Error('not adult')
});
Probably you got something like (node:5009) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Looks like you run your asyncFunc(..) in console. In this case node.js first execute your function after your hit Enter. Try to take your code to curly brackets like this:
{
asyncFunc('Sample String')
.then(result => { console.log(result); })
.catch(error => { console.log(error); });
}
In case of a try/catch block you usually reject at catch but you can also reject in try.
resolve and reject are basically callbacks for Promise. if you resolve it will got to the next chain if you reject it will break the chain.
So should use reject when an error occurs cause reject will break the promise chain.
For example.
Lets say you have a function that works with callback and you want to wrap it in a Promise like function. This function will check if user exists in database. If the User is found it will return true if not false and if there is an error in database (eg connection) it will reject.
function checkUserExist(id) {
return new Promise((resolve, reject) => {
checkUserExistInDatabase(id, function(result, error) {
if (error) {
reject(error);
}
if (result != null) {
resolve(true);
} else {
resolve(false);
}
})
});
}
function databaseError() {
return new Promise((resolve, reject) => {
reject();
})
}
var idsThatExist = [];
checkUserExist(1).then(function(exist) {
if (exist)
idsThatExist.push(1);
return checkUserExist(2)
}).then(function(exist) {
if (exist)
idsThatExist.push(2);
return databaseError(3)
}).then(function(exist) {
//WILL never Reach here
if (exist)
idsThatExist.push(3);
return checkUserExist(4)
}).then(function(exist) {
if (exist)
idsThatExist.push(4);
}).catch(function(err) {
//it will skip checkUserExist(4)
console.log('I got rejected after checked users:'
idsThatExist)
})
So the question is "reject" can only be used from "catch" block?
No, You can use reject anywhere. Catch isn't necessary to use reject
Why can't I raise "reject" event manually?
You can reject using creating new Promise() or static methods of Promise . See promiseUsingNew() and promiseUsingStaticMethod()
What is the scenario "reject" is used?
try/catch is used for error handling in synchronous programming. resolve & reject is for error handling in asynchronous programming operation instead of callbacks.
Can someone provide me a better example where I can use both "resolve" and "reject"?
'use strict';
function promiseUsingNew(marks) {
return new Promise((resolve, reject) => {
if (marks < 0 || marks > 100) {
return reject('Invalid marks');
}
if (marks >= 40) {
return resolve('You passed');
} else {
return resolve('You Failed');
}
});
}
function promiseUsingStaticMethod(marks) {
if (marks < 0 || marks > 100) {
return Promise.reject('Invalid marks');
}
if (marks >= 40) {
return Promise.resolve('You passed');
} else {
return Promise.resolve('You Failed');
}
}
// you can use promiseUsingNew(marks) or promiseUsingStaticMethod(marks)
promiseUsingNew(221).then((result) => {
console.log(result);
}).catch((error) => {
console.log(error);
});

Resources