Why does delaying handling of promise rejections sometimes result in UnhandledPromiseRejectionWarning? - node.js

When I run the following code, why do I get unhandled promise rejection warning?
async function load() {
throw new Error('error');
}
async function main() {
const promise = load();
await new Promise(resolve => setTimeout(resolve, 5000));
try {
await promise;
} catch (e) {
console.log('caught error', e);
}
}
main();
This is the output:
jkim#dev-jkim test $ node index.js
(node:25276) UnhandledPromiseRejectionWarning: Error: error
Since await promise is around a try-catch, I'm confused why my try-catch isn't catching the error. I guess it's something to do with the setTimeout since the following code works:
async function load() {
throw new Error('error');
}
async function main() {
const promise = load();
try {
await promise;
} catch (e) {
console.log('caught error', e);
}
}
main();
jkim#dev-jkim test $ node index.js
caught error Error: error
What is going on here? If promise rejections are not handled by the end of the current tick, does it automatically result in a unhandled promise rejection warning?
(I'm on node v10.16.3)

If promise rejections are not handled by the end of the current tick, does it automatically result in a unhandled promise rejection warning?
Yes. A Promise must have a rejection handler attached to it at the moment it rejects, or the rejection will count as unhandled. If you attach the rejection handler later, such as after a
await new Promise(resolve => setTimeout(resolve, 5000));
the load Promise has rejected by the time the interpreter gets to the
try {
await promise;
} catch (e) {
so, although the rejection can be caught with .catch, it wasn't caught by anything at the moment of rejection, resulting in the warning.
Best practice for this sort of thing is to always attach a rejection handler immediately - whether that means .catch, or inside a try/catch, or a Promise.all, or returning the Promise for the caller to handle.

The function load() throws an Error. When an error is thrown while a Promise is being handled, the Promise is rejected. Now, if the Error load() threw is not caught then, a UnhandledPromiseRejectionWarning is thrown by JS
A better Illustration of your code is:
function load() {
console.log("hello after some time");
}
const foo = new Promise((resolve, reject) => {
setTimeout(resolve, 5000);
})
.then(() => { load(); })
.catch((e) => { console.log(`Caught Error: ${e}`)});

Related

unhandled promise rejection when running whatsapp bot

I'm running a whatsapp bot and everything works fine until I get a message
at /root/bot/node_modules/#adiwajshing/baileys/lib/Utils/generics.js:157:32
(node:26706)
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(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 21)
I tried to search for some answers on the ChatGPT bot but that's not working, maybe someone can help me to fix this issue.
Here is the code
// Create a promise that rejects in <ms> milliseconds
const { delay, cancel } = (0, exports.delayCancellable)(ms);
const p = new Promise((resolve, reject) => {
delay
.then(() => reject(new boom_1.Boom('Timed Out', {
statusCode: Types_1.DisconnectReason.timedOut,
data: {
stack
}
})))
.catch(err => reject(err));
promise(resolve, reject);
})
.finally(cancel);
return p;
}
Note: code at
root/bot/node_modules/#adiwajshing/baileys/lib/Utils/generics.js:157
is
.then(() => reject(new boom_1.Boom('Timed Out', {

MongooseError: Query was already executed: User.countDocuments({})

(node:9540) UnhandledPromiseRejectionWarning: MongooseError: Query was already executed: User.countDocuments({})
at model.Query._wrappedThunk [as _countDocuments] (D:\Acadamic-LANGUAGE-PROJECTS\Angular-Projects\eShop-MEAN STACK\Back-End\node_modules\mongoose\lib\helpers\query\wrapThunk.js:21:19)
at D:\Acadamic-LANGUAGE-PROJECTS\Angular-Projects\eShop-MEAN STACK\Back-End\node_modules\kareem\index.js:370:33
at processTicksAndRejections (internal/process/task_queues.js:77:11)
(Use node --trace-warnings ... to show where the warning was created)
(node:9540) 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(). To terminate the node
process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:9540) [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.
this is my Code......
router.get(`/get/count`, async (req, res) =>{
const userCount = await User.countDocuments((count) => count)
if(!userCount) {
res.status(500).json({success: false})
}
res.send({
userCount: userCount
});
})
It seems that you are using Mongoose. It seems you are mixing between async-await and callbacks.
Change await User.countDocuments((count) => count) to
await User.countDocuments()
This is because countDocuments() is called using its callback (which passes its result to the callback), while on the other hand, it is also asked to pass its result to the userCount variable using the await command.
This is exactly what this error message is trying to say: hey, you're sending the same query to the database twice ! While, since since v6 of Mongoose, you can only get run query once - ie, either by adding the cbk argument, or using async-await block. Read about it here: https://mongoosejs.com/docs/migrating_to_6.html#duplicate-query-execution
Now let's move ahead to fixing the problem:
I don't completely understand what you're trying to do this in line:
const userCount = await User.countDocuments((count) => count)
I think what you're trying to do is just get the document count. If so, simply drop 'count => count'.
router.get(`/get/count`, async (req, res) =>{
const userCount = await User.countDocuments();
if(!userCount) {
res.status(500).json({success: false})
}
res.send({
userCount: userCount
});
})
If you were to add a filter to the count (which is what the countDocuments gets - a filter; see API here), then you should use the key:value pair form, ie {count: count}.
router.get(`/get/count`, async (req, res) =>{
/* let count; etc. */
const userCount = await User.countDocuments({count: count});
if(!userCount) {
res.status(500).json({success: false})
}
res.send({
userCount: userCount
});
})
Of course you should use a proper try-catch block when using await, to be able to handle the error if thrown.
(Just encountered this problem myself and made some research into it.)
module.exports.getUserCount = async(req,res)=>{
const numberOfUser = await User.countDocuments()
res.send({numberOfUser : numberOfUser});
}

Unhandled Promise Rejection Warning Occured

I want to create Product Categories , so i handle it in productController class database call in productCatService class. I added JS promise to this . now it gives following error.
productCatController.js
module.exports.createProductCat = async (request, response)=> {
let result = await productCatService.createProductCat(productCatData);
if (result) {
responseService.successWithData(response, "Product Category Created");
} else {
responseService.errorWithMessage(response, result);
}
}
productCatService.js
module.exports.createProductCat = (productCatData) => {
let productCat = {
name: productCatData.name,
desc: productCatData.desc,
count:productCatData.count,
status : productCatData.status
};
return new Promise((resolve,reject)=>{
ProductCategory.create(productCat).then(result => {
resolve(true);
}).catch(error => {
reject(false)
})
});
}
Error
(node:18808) UnhandledPromiseRejectionWarning: false
(Use `node --trace-warnings ...` to show where the warning was created)
(node:18808) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a p
romise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.
html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:18808) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a no
n-zero exit code.
Never use await without try/catch. You don't have to try/catch every await, but somewhere down the call stack there needs to be a try/catch block.
You don't need try/catch here, just return the promise from ProductCategory.create()...
// productCatService.js
module.exports.createProductCat = (productCatData) => ProductCategory.create({
name: productCatData.name,
desc: productCatData.desc,
count: productCatData.count,
status: productCatData.status
});
...but you definitely need try/catch here, as this function is the bottom of the stack for this operation, and it is responsible for signifying overall success or failure to the caller.
// productCatController.js
module.exports.createProductCat = async (request, response) => {
try {
await productCatService.createProductCat(productCatData);
responseService.successWithData(response, "Product Category Created");
} catch (err) {
responseService.errorWithMessage(response, err);
}
}
Also don't use new Promise() for operations that already are promises. Keep using the promise you already have. Wrapping new Promise() around existing promises is a source of useless bloat, and it can introduce subtle bugs. Avoid.

proxyReq.setHeader can not set headers after they are sent

i am building a node.js proxy and i want to add a conditional header
proxy.on('proxyReq', (proxyReq, req, res) => {
const realIP = parseHttpHeader(req.headers['x-real-ip'])[0];
const path = parseHttpHeader(req.headers['x-original-uri'])[0];
pAny([
check_ip(realIP) ,
check_path(path) ,
check_geo(realIP)
]).then(result => {
console.log (result , "result " )
if (result) {
proxyReq.setHeader('namespace' , 'foo');
} else {
proxyReq.setHeader('namespace' , 'bar'); }
console.log('sending req ')
});
});
.
async function check_ip(realIP) {
try {
const result = await ipModel.findOne({ip: realIP}).exec()
console.log(realIP , result , "ip")
if (result) {
return true
} else {
return false
}
} catch (e) {
throw e;
}
}
and it works just fine till i use the methos check_ip then i get the error
(node:3793) UnhandledPromiseRejectionWarning: Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ClientRequest.setHeader (_http_outgoing.js:498:3)
at /home/master/IPS/server.js:109:14
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:189:7)
(node:3793) 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:3793) [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.
as the error clearly states i am handeling a promise in the wrong way but i don't know how to fix it i tried using callbacks i tried using await
make the check_ip return a promise and try
function check_ip(realIP) {
return ipModel.findOne({ ip: realIP }).exec();
}

loopback async/await UnhandledPromiseRejectionWarning issue

In loopback 3 When i implement async/await in the before save Operation hook
Entry.observe('before save', async (ctx, next) =>{
if(ctx.instance.images){
Entry.upload(ctx.instance.images[0].src).then(data => {
ctx.instance.image = data;
});
}
});
the console print this error
(node:29323) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Callback was already called.
(node:29323) 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.
How can i get rid of this issue!?
PS. i cant figure out where's that promise, and this message disappear once i remove the async/await.
You need to specify .catch for the Entry.upload promise.
Entry.upload(ctx.instance.images[0].src).then(data => {
ctx.instance.image = data;
}).catch(console.error);
Some older versions of NodeJS probably won't have that error. You need to always use catch for promises, otherwise the app will crash.
Use try/catch block and always return a Promise resolved or rejected when declare async function (or Promise function)
Entry.observe('before save', async (ctx) =>{
try {
ctx.instance.image = await Entry.upload(ctx.instance.images[0].src)
} catch(error){
return Promise.reject(error)
}
return Promise.resolve()
});

Resources