Mysterious unhandled promise warning from NodeJS [duplicate] - javascript

This question already has answers here:
Waiting for more than one concurrent await operation
(4 answers)
Closed 3 years ago.
When the below code errors (ping() rejects its promise), I get the warning. The HTTP function seems to error out just fine. Something must be happening in ping() itself, I guess, which is somehow avoiding the try-catch.
Could someone enlighten me? (This is after a few attempts at changing things to get it working.)
(async () => {
try {
let webTask, pingTask;
try {
webTask = httpsGet(urls[0]);
} catch (e) {
console.log(e);
}
try {
pingTask = ping('8.8.8.8');
} catch (e) {
console.log(e);
}
try {
const webResult = await webTask;
console.log('HTTP result:', webResult);
} catch (e) {
console.log(e);
}
try {
const pingResult = await pingTask;
console.log('Ping result:', pingResult);
} catch (e) {
console.log(e);
}
} catch (e) {
console.log('Error:', e);
}
})();
The error is:
"main.js" 137 lines, 2945 characters
(node:58299) UnhandledPromiseRejectionWarning: #<Object>
(node:58299) 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:58299) [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 earlier in the file where I define my ping function:
const netping = require('net-ping');
const pingSession = netping.createSession({
retries: 0,
timeout: 10000
});
const ping = ip => {
return new Promise((resolve, reject) => {
let result = { ipAddress: ip, start: new Date(Date.now()), end: null, error: null, duration_ms: -1 };
pingSession.pingHost(ip, (error, target) => {
result.end = new Date(Date.now());
result.duration_ms = result.end - result.start;
if (error) {
result.error = error;
console.log('rejecting promise');
reject(result);
} else {
resolve(result);
console.log('resolving promise');
}
});
});
};
NodeJS 11.13.0

await is the javascript construct which converts the rejection of the promise to an exception.
That is, await is the construct which handles the rejection.
When you write:
try {
pingTask = ping('8.8.8.8');
} catch (e) {
console.log(e);
}
There's no await there, so there's nothing to convert the rejection to an exception, or indeed to handle the rejection in any way.
If you're going to call ping() without waiting, then you need a more explicit rejection handling.
EDIT
Here's a minimal reproducer:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const test = (ms, msg) => {
return new Promise((resolve, reject) => {
sleep(ms).then(reject(msg)).catch(console.log);
});
};
(async () => {
let task1;
try {
const ms = 50;
task1 = test(ms, "hey");
await sleep(ms * 2); // otherwise you don't get an error
await task1;
} catch (e) {
console.log(e);
}
})().then(console.log).catch(console.log);
(node:12822) UnhandledPromiseRejectionWarning: hey (node:12822)
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:12822) [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. hey undefined (node:12822)
PromiseRejectionHandledWarning: Promise rejection was handled
asynchronously (rejection id: 1)
The Promise() constructor starts running test(), after 50 ms the promise is rejected but there is nothing to convert the rejection to an exception.
If we remove the 100 ms sleep, then await registers its "convert rejection to exception" logic onto the promise way before the 50 ms sleep is done, and so when the promise gets rejected ~49 ms after await was called, there's a handler to convert it to an exception.

Related

UnhandledPromiseRejectionWarning when re-throw error from inner catch to outer catch

I use Node Js 12. I have below code and error. I want to re-throw err from inner catch and catch it in outer one. How to modify my code to achieve error re-throw?? Thanks.
function test() {
try {
// Some other code before promise chain below that could cause exception
return Promise.resolve()
.then(() => {
const e = new Error();
e.message = 'testtest';
e.statusCode = 404;
throw e;
})
.catch(err => {
console.log('==inner===', err);
throw err;
});
} catch (err) {
console.log('==outer===', err);
}
}
test();
Error
jfan#ubuntu2004:~/Desktop/temp/d$ node index.js
==inner=== Error: testtest
at /home/jfan/Desktop/temp/d/index.js:17:19 {
statusCode: 404
}
(node:34826) UnhandledPromiseRejectionWarning: Error: testtest
at /home/jfan/Desktop/temp/d/index.js:17:19
(node:34826) 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:34826) [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.
jfan#ubuntu2004:~/Desktop/temp/d$
SUGGESTION
// define an async function for the purpose of awating a promise inside the function
// optional useError parameter is used to trigger an error for testing purposes
// optional args parameter is for passing any additional parameters to this function for example
async function test(useError=false, args=[]) {
try {
// Some other code before promise chain below that could cause exception
if(useError) {
throw new Error(`Some error occured while processing ${args[0]}...`);
}
// await the promise and store the result in a variable
const promisedData = await Promise.resolve(`Promise delivered with ${args[0] ? args[0] : 'nothing'}!`);
// return the result (this will be a promise)
return promisedData;
} catch (err) {
// catch error that occurs within try block
console.log('==outer===', err);
}
}
// a simple generic async function runner for example
async function genericAsyncFunctionRunner(asyncFunction, ...args) {
let [useError, ...otherArgs] = args;
useError = useError ? true : false;
const result = await asyncFunction(useError, otherArgs);
// Output the result in console for example
console.log(result);
}
// run asyn function using the generic async function runner with/without arguments
genericAsyncFunctionRunner(test); // Promise delivered with nothing!
genericAsyncFunctionRunner(test, false, 'gratitude'); // Promise delivered with gratitude!
genericAsyncFunctionRunner(test, true, 'gratitude'); // ==outer=== Error: Some error occured while processing gratitude...

How I can return promise(reject) from catch block of async/await method?

I am calling a callback method from async method and then that async method is been called by another and then another async method.
I tried using new return Promise.reject(new Error(error));
but it does not work.
async function getBookDescription(bookid){
logger.info("Inside getBookDescription");
if(booked){
var getBookDocPromise = promisify(MongoModel.getByBookID);
return await getVaultDocPromise(bookid)
}else{
var getDefaultBookPromise = promisify(MongoModel.getDefaultBookConfigs);
return await getDefaultBookPromise();
}
}
async function getbookdetails(bookid, credentials){
logger.info("Inside getbookdetails");
var errMessage;
try {
try{
var bookdetails = await getBookDescription(bookid);
}catch (error) {
logger.info("error"+JSON.stringify(error));
return Promise.reject(new Error(error));
}
if(bookdetails && bookdetails >0){
logger.info("got the bookdetails");
return bookdetails;
}else{
logger.info("inside error");
errMessage = {
"message": bookDetailsNotFound
}
logger.error(errMessage.message);
return errMessage
}
} catch (error) {
return error
}
}
async function addbooks(req,res){
logger.info("Inside addbooks()");
try {
var result = await getbookdetails(bookId);
return res.status(result.statusCode).send(result.message);
} catch (error) {
logger.info("inside error");
return res.status(error.statusCode).send(error);
}
}
expected --> in case when got error from getBookDescription it should throw reject and addbooks catch should be called.
Actual-->UnhandledPromiseRejectionWarning: TypeError: code argument is required to res.status
at ServerResponse.status (/Users/mayank/Documents/work/git/cb-credential-service/node_modules/express/lib/response.js:68:11)
at addCredsToVault (/Users/mayank/Documents/work/git/cb-credential-service/src/app/v2/api/credential-reference-api.js:55:22)
at
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
(node:25108) 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: 7)
(node:25108) [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.

Getting UnhandledPromiseRejectionWarning despite several `try`-`catch` blocks

I'm using a 3rd party module that wraps around their API. I have the following code:
const api = require('3rdpartyapi');
async function callAPI(params) {
try {
let result = await api.call(params);
return result;
}
catch(err) {
throw err; //will handle in other function
}
}
async function doSomething() {
try {
//...do stuff
let result = await callAPI({a:2,b:7});
console.log(result);
}
catch(err) {
console.error('oh no!', err);
}
}
Despite both try-catch blocks, the 3rd party API, when it losses connection to homebase (happens quite frequently :( ), blows up with:
(node:13128) UnhandledPromiseRejectionWarning: FetchError: request to https://www.example.com failed, reason: getaddrinfo ENOTFOUND
Followed by:
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)
How come none of my try-catch catch this? What exactly is unhandled, and how to actually handle this?
The point is the await only converts "first layer" rejection into error, however the promise can have promise inside, and their library may fail to catch the rejection inside. I have made a proof of concept 3rdpartyapi which can trigger the behavior you see:
(async function () {
// mock 3rdpartyapi
var api = {
call: async function(){
await new Promise((resolve, reject) => {
// why wrap a promise here? but i don't know
new Promise((innerResolve, innerReject) => {
innerReject('very sad'); // unfortunately this inner promise fail
reject('this sadness can bubble up');
})
})
}
};
// your original code
async function callAPI(params) {
try {
let result = await api.call(params);
return result;
} catch (err) {
throw err; //will handle in other function
}
}
async function doSomething() {
try {
//...do stuff
let result = await callAPI({
a: 2,
b: 7
});
console.log(result);
} catch (err) {
console.error('oh no!', err);
}
}
doSomething();
})();
Output:
$ node start.js
oh no! this sadness can bubble up
(node:17688) UnhandledPromiseRejectionWarning: very sad
(node:17688) 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:17688) [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.

setInterval and promises yields a PromiseRejectionHandledWarning

I have an application where I continuously have to run some async code in the background. I created a minimal simulation of my application.
let promise_chain = Promise.resolve();
let rejected_promise_count = 0;
const interval_id = setInterval(
// Do some important polling. I will just always reject to demonstrate the problem.
() => {
promise_chain = promise_chain.then(() => {
rejected_promise_count += 1;
return Promise.reject();
})
},
10
);
// Set timeout simulates the program being done.
setTimeout(
() => {
clearInterval(interval_id);
promise_chain
.then(() => end("Resolved! :D"))
.catch(() => end("Rejected! D:"));
},
1000
);
function end(message) {
console.log(message);
console.log(`Amount of rejected promises created: `, rejected_promise_count);
}
This gives a long list of these:
(node:29217) UnhandledPromiseRejectionWarning: undefined
(node:29217) 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:29217) [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.
(node:29217) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 2)
(node:29217) UnhandledPromiseRejectionWarning: undefined
(node:29217) 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)
(node:29217) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 3)
(node:29217) UnhandledPromiseRejectionWarning: undefined
(node:29217) 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:29217) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 4)
Eventually ended by these:
(node:29217) UnhandledPromiseRejectionWarning: undefined
(node:29217) 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: 87)
(node:29217) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 87)
(node:29217) UnhandledPromiseRejectionWarning: undefined
(node:29217) 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: 88)
Rejected! D:
Amount of rejected promises created: 1
(node:30920) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 89)
I'm not quite sure why node doesn't want me to handle these asynchronously, but given it runs on an interval, I really have no other choice.
How do I get rid of the endless list of warnings, and more importantly, how do I make sure in the future node will not terminate this process because it thinks I am not handling the rejections?
It depends what you want to do, the correct way to handle it is like this:
const interval_id = setInterval(
() => {
promise_chain = promise_chain.then(() => {
rejected_promise_count += 1;
return Promise.reject();
});
//ignore error here, you catch it in the setTimeout
promise_chain.catch(ignore=>ignore);
},
10
);
That will output:
Rejected! D:
Amount of rejected promises created: 1
This because you reject the first time so the chain is broken and all other then are not executed.
If you would like to continue executing and want to know how many passed and failed you can do something like this:
//using actual results
let results = [];
//special Fail value to indicate rejected promise
let Fail = function(reason){this.reason=reason;};
let isFail = object=>(object&&object.constructor===Fail);
let isNotFail = object=>!isFail(object);
let promise_chain;
let somePromise = ()=>Promise.reject(new Error("Some reason"));
const interval_id = setInterval(
() => {
promise_chain = (promise_chain||somePromise())
.then(
result => {
results.push(result);
return somePromise();
}
)
.catch(//catch the rejection and return a Fail type value
error=>new Fail(error)
);
},
10
);
// Set timeout simulates the program being done.
setTimeout(
() => {
clearInterval(interval_id);
promise_chain
.then(
result => {
//add the last result to results
results.push(result);
console.log(
"rejected promises:",
results.filter(isFail).length
//you can get the errors like so:
//results.filter(isFail).map(fail=>fail.reason)
);
console.log(
"resolved promises:",
results.filter(isNotFail).length
//results.filter(isNotFail) is an array of resolved values
)
}
);
//this will never reject because we catch rejected promises
// and add fail types to results
// .catch(() => end("Rejected! D:"));
},
1000
);

Debug Unhandled Promise Rejections

I have written to following db query to get back all posts with a certain offset:
async function getPaginationPosts(start, size) {
try {
const posts = await knex("posts").select().where({
deleted: false,
}).orderBy("createdAt").limit(size).offset(start)
} catch (e) {
console.log(e.message)
console.log(e.stack)
}
return posts
}
However, I am getting the following Unhandled Promise Rejection
(node:1824) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ReferenceError: posts is n
ot defined
(node:1824) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejection
s that are not handled will terminate the Node.js process with a non-zero exit code.
My problem is that I do not get any further information about the error in the console.
Any suggestions from your site:
How to debug these types of rejections properly?
What is wrong with the above code?
Thank you in advance for your replies!
Update
I changed my function to the following:
async function getPaginationPosts(size, offset) {
try {
return await knex("posts").select().where({
deleted: false,
}).orderBy("createdAt").limit(size).offset(offset)
} catch (e) {
console.log(e.message)
console.log(e.stack)
return null
}
}
Now I am getting the following exception:
(node:9096) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ReferenceError: start is n
ot defined
I do not use a variable start in my function.
Any suggestions what I am doing wrong here?
A convenient way to log unhandled rejections - is to add listener (usually at entry point of your app, i.e. main.js) that looks like this
process.on("unhandledRejection", (error) => {
console.error(error); // This prints error with stack included (as for normal errors)
throw error; // Following best practices re-throw error and let the process exit with error code
});
posts are defined not in the correct place. Define them outside of try/catch block or return result from try block:
async function getPaginationPosts(start, size) {
try {
return await knex("posts").select().where({
deleted: false,
}).orderBy("createdAt").limit(size).offset(start)
} catch (e) {
console.log(e.message)
console.log(e.stack)
return null
}
}
Or:
async function getPaginationPosts(start, size) {
let posts
try {
posts = await knex("posts").select().where({
deleted: false,
}).orderBy("createdAt").limit(size).offset(start)
} catch (e) {
console.log(e.message)
console.log(e.stack)
}
return posts
}

Categories