(node:5151) UnhandledPromiseRejectionWarning - node.js

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);
});

Related

Handling Unhandled promise rejection in express application

I have an existing Node Express Application and want to improve the error handling better. My current route endpoint definition is like below,
app.get('/example/getActiveId', async (req, res, next) => {
// Some code to fetch some details from request and do some validations
try {
const result = await api.getActiveId(id);
res.json({ success: true, result }); // I am getting this response in all the time.
} catch (err) {
console.log('getActiveId', err)
console.error(err);
res.json({ success: false });
}
});
Also, I defined error middleware at the last of all the route paths.
// error handler middleware
app.use((error, req, res, next) => {
console.log('in Error middleware')
console.error(error.stack);
res.status(500).send(error.message || 'Something Broke!');
})
My definition of getActiveId is as below.
exports.getActiveId = id => axiosInstance
.get('/example')
.then(({ data }) => data)
.catch(er => er);
The problem in the above getActiveId definition is every time the catch of the getActiveId, the execution falls into the try block of the above endpoint definition. I wanted the execution should go into the catch block endpoint definition function. So that I could call next(err) to call the default express error handling middleware.
So I tried the following mockup code to mimic the same with promise reject.
exports.getActiveId = id => {
const __mockPromise = () => {
return new Promise((resolve, reject) => {
reject('Problem in getActiveId')
})
}
return new Promise((resolve, reject) => {
__mockPromise().then(({ data }) => resolve(data)).catch(er => { console.log('in catch....'); reject(er) })
});
}
I expected the above function will go into the catch block of the end point function definition.
But this time I am getting the following error,
in catch....
(node:32897) UnhandledPromiseRejectionWarning: Problem in getActiveId
(node:32897) 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)
How can I fix this error and bypass the execution to error middleware?
With your current code, api.getActiveId always returns a resolved promise
if the axiosInstance.get succeeds, it resolves to the data
if the axiosInstance.get fails, the .catch(er => er) makes it resolve to the er.
If you want api.getActiveId to return a promise that is rejected with er, omit the .catch(er => er).
For example, if you run Node.js with the following input
const getActiveId = () => Promise.reject("error")
.then(({ data }) => data);
async function test() {
try {
const result = await getActiveId();
console.log(result);
} catch (err) {
console.error(err);
}
}
test();
the console.error statement will be reached and no unhandled promise rejection will be reported.

catch(err) giving error but do not return object data in async function in node express js

I'm using node v10.19.0 and i have created async function (req) {} it has try catch block if the error occur, then it console the error but cant return that error.
In routes.js: router.post("/somefunction", middleware.somefunction);
In middleware.js:
module.exports.somefunction = async (req, res) => {
var someFuncResponse = await service.someFunction(req)
res.send(someFuncResponse)
}
In service.js:
module.exports.someFunction = async function (req) {
try{
//some code which gives error
let response = { id:1 }
return { status: true, data: response }
}catch(error){
// catches the error
let response = { id:2 }
console.log(error) // get print correctly
console.log(response) // get print correctly
return { status: false, data: response } //not returning this
}
}
when i am hit this api on postman, i am getting "Could not get response" message.
also i am getting below msg on console:
(node:55009) 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: 1)
(node:55009) [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.
Try to wrap return values with Promise.resolve:
module.exports.someFunction = async function (req) {
try{
//some code which gives error
let response = { id:1 }
return Promise.resolve({ status: true, data: response })
}catch(error){
// catches the error
let response = { id:2 }
console.log(error) // get print correctly
console.log(response) // get print correctly
return Promise.resolve({ status: false, data: response }) //not returning this
}
}

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.

NodeJS Error Handling - Throwing error promise to try catch

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);
})
}

Use of async and await to handle promise

I want to use async and await to handle the promises. I would like to use this on the given example below:
exports.getUserData = async function(userId){
let query = {};
if(userId){
query.where = {userid : req.query.id}
}
let data;
try{
data = await entity.DB_User.findAll(query);
}catch(error){
console.log(error);
}
}
On execution its giving me an error
Error:
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: 3)
First thing first, you should return data.
I think that the Exception is raised when you call getUserData. Try:
getUserData()
.then(data => console.log)
.catch(err => console.log) // this line prevent the UnhandledPromiseRejection
// or in async context
try {
const data = await getUserData()
console.log(data)
} catch (err) {
console.log(err)
}

Resources