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

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.

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...

Mysterious unhandled promise warning from NodeJS [duplicate]

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.

UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1) in Node.JS

Hi I am trying to call async function makeRemoteExecutableSchema which returns promise.
async function run() {
const schema = await makeRemoteExecutableSchema(
createApolloFetch({
uri: "https://5rrx10z19.lp.gql.zone/graphql"
})
);
}
I am calling this function in the constructor.
class HelloWorld {
constructor() {
try {
run();
} catch (e) {
console.log(e, e.message, e.stack);
}
}
}
I am getting this error. Does anyone know how to resolve this ?
(node:19168) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'getQueryType' of undefined
(node:19168) [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.
If makeRemoteExecutableScheme() returns a promise that eventually rejects, then you have no code to handle that rejection. You can handle it one of two ways:
async function run() {
try {
const schema = await makeRemoteExecutableSchema(
createApolloFetch({
uri: "https://5rrx10z19.lp.gql.zone/graphql"
})
);
} catch(e) {
// handle the rejection here
}
}
Or here:
class HelloWorld {
constructor() {
run().catch(err => {
// handle rejection here
});
}
}
You use try/catch around an await and within the same function. One run() has returned, you're just dealing with a promise at that point so you would catch the rejection there with .catch(), not with try/catch.
It's important to remember that await is syntactical sugar for .then() within a function only. It does not apply any magic beyond that function. Once run() returns, it's just returning a regular promise so if you want to catch the rejection from that returned promise, you have to either use .catch() on it or await it again and then surround it with try/catch. Surrounding a non-awaited promise with try/catch does not catch rejected promises which is what you were doing.

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
}

Unhandled promise rejection from promise called within Try

I have a promise function called findProperty which in this case rejects like this:
reject('ERR: Unknown propertyID or inactive property in call of newBooking');
And this is my handler that calls findProperty:
async function main() {
var res = "";
try {
findProperty();
res = await findUser(userEmail);
res = await findUser(agentEmail);
res = await getUsers();
}
catch(err) {
console.error(err);
console.log(" newBooking: " + err);
callback( { error:true, err } );
}
}
main();
This causes the following error:
(node:10276) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ERR: Unknown propertyID or inactive property in call of newBooking
(node:10276) [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.
I dont get this, I got my catch(err) shouldn't that be enough?
Just tried something, this works fine:
resolve('ERR: Unknown propertyID or inactive property in call of newBooking');
But this gives the error:
reject('ERR: Unknown propertyID or inactive property in call of newBooking');
If findProperty returns a promise, you need to await it in order to trigger the failure within the context of the async function; otherwise the rejection disappears into outer space.
To "fire and forget" without waiting, yet catch failures with your try/catch:
findProperty().catch(e => { throw e; });

Categories