I seem to have a chained catch block for handling promise rejection (and it does catch the rejection ok) but I still see the warning about unhandled promise rejection. What am I not getting right here?
Promise.resolve(req.query.request_token)
.then(function(rt) {
request_token = rt+'2'
return kc.generateSession(request_token, api_secret)
})
.then(function(resp) {
console.log(resp)
return kc.setAccessToken(resp.access_token)
})
.then(() => console.log(kc))
.catch(err => console.error(err))
So, I tried recreating this example and seeing if something is wrong with your promise chain, but I don't think there is because my below example works fine, ie: I tried throwing errors, and rejecting each one of the mock functions but no matter what I do in the mock functions, the 'this happens here' still gets printed.
function testResolve() {
return new Promise((res, rej) => res(1))
}
function generateSession(a, b) {
return new Promise((res, rej) => {
console.log(a)
console.log(b)
res(`a: ${a}, b: ${b}`)
})
}
function setAccessToken(token) {
return new Promise((res, rej) => {
res(1)
})
}
Promise.resolve(testResolve())
.then(function(rt) {
var request_token = rt+'2'
return generateSession(request_token, 'a1')
})
.then(function(resp) {
console.log(resp)
return setAccessToken(resp.access_token)
})
.then(() => console.log(x))
.catch(err => {
console.log('this happens here')
console.error(err)
})
I would check the unhandled promise rejection message and see the line number that it gives you, and look at the filename where the error occurred. It's possible that there was an unhandled rejection inside code somewhere else, because as far as I know this promise chain should catch any errors that happen anywhere in the chain.
Related
I have a Nodejs cron job that runs every 5 seconds:
cron.schedule("*/5 * * * * * *", async function() { //Every 5 seconds
try{
await cleanUpDatabase()
}
catch(err){
console.log(err)
console.trace(err.lineNumber)
}
});
async function cleanUpDatabase(){
let pool = await connection;
pool.query(`SELECT * FROM table1`)
}
I do not have a table named table1 in my database. I want the second function to produce an error
But from my understanding of try catch block since the function that is calling the cleanUpDatabase function has catch statement it should catch the error even though there is no try catch on cleanUpDatabase function. However it does not catch it
In my express application I have a function that displays all unhandled rejection:
process.on('unhandledRejection', (error, p) => { //I added this so that I can console log the unhandled rejection and where it is coming from. Before this I would just get UnhandledPromiseRejectionWarning: Unhandled promise rejection without knowing which promise was not handled
console.log('=== UNHANDLED REJECTION ==='); // Not good to have unhandled promise rejection in code. This will just help me locate it incase here is one
console.dir(error.stack);
});
This function is catching the error. Which means that the error is not handled. The error that I am getting is:
=== UNHANDLED REJECTION === "RequestError: Invalid object name 'table1'.\n"
Why is the parent function not able to handle the error?
Edit 1:
Even this does not work. I'm really confused now
async function cleanUpDatabase(){
try{
let pool = await connection;
pool.query(`SELECT * FROM table1`)
}
catch(err){
throw err;
}
}
Try this:
function cleanUpDatabase() {
return new Promise(async (resolve, reject) => {
let pool = await connection;
pool.query(`SELECT * FROM table1`);
resolve();
}).catch((error) => {
console.log(error);
});
}
This question already has an answer here:
Why are exceptions used for rejecting promises in JS? [closed]
(1 answer)
Closed 2 years ago.
In node.js, is there a good explanation of how exceptions work in conjunction with 'rejection' of promises?
Promise rejection is the asynchronous analogue to exceptions in synchronous code. An exception thrown inside a promise handler (be it in then(), catch() or finally()) is automatically converted to a promise rejection.
However, the opposite is not true. If you create a promise, or call a function that returns a promise that will ultimately be rejected, within a try/catch block there is no automatic conversion to an exception. But you can do it using async/await. This will work:
async function() {
try {
await getPromiseThatWillBeRejected();
}
catch (e) {
// error that caused rejection can be handled here
}
}
The await keyword virtually converts this to a synchronous blocking call (it is not really blocking but subsequent code is only executed after the promise is fulfilled or rejected) and converts the rejection to a synchronous exception.
The following is a walkthrough of the combinations of exceptions and promise rejections.
Let's start with a promise that throws an exception, and another that completes the promise with a rejection, to compare them.
function thrower() {
return new Promise((resolve, reject) => { throw new Error('thrown'); });
}
function rejecter() {
return new Promise((resolve, reject) => reject('rejected'));
}
The following calling code will receive the error in the same way:
thrower.catch(ex => console.log('caught ' + ex));
rejecter.catch(ex => console.log('caught ' + ex));
The result is caught Error: thrown and caught rejected. An exception reaching the catch function is straight forward. But it is strange that a rejected promise ends up in a catch function too. That's how it is, let's move on.
Similarly, an exception becomes a rejection. The following uses the second parameter of then to provide an onrejection function:
thrower().then(() => {}, err => console.log('err ' + err));
rejecter().then(() => {}, err => console.log('err ' + err));
Result is err Error: thrown and err rejected. Again, this makes sense, rejections reach the onrejection handler. It's a stretch, but meh sure, that exceptions land there too.
Now what if both onrejection handler and catch are used?
thrower().then(() => {}, err => console.log('err ' + err)).catch(ex => console.log('caught ' + ex));
rejecter().then(() => {}, err => console.log('err ' + err)).catch(ex => console.log('caught ' + ex));
The outcome is err Error: thrown and err rejected. Here it is somewhat confusing. The language routes the exception into the err function, and not to the catch function.
An important point, this code does not catch the exception:
try {
thrower();
}
catch(ex) {
console.log('caught ' + ex); // won't catch thrower's exception
}
Why of course - the try/catch block execution completes before the promise is executed.
But it is less obvious that this doesn't work either:
function throwerThrower() {
return new Promise((resolve, reject) => { thrower().catch(ex => { throw ex }); });
}
throwerThrower().catch(ex => console.log('caught ' + ex)); // not going to catch nested throw
Cascading an exception like above will result in an unhandled exception.
However this next block does work and maybe shows how valuable it is to reject instead of throw:
function throwerRejecter() {
return new Promise((resolve, reject) => { thrower().catch(ex => reject(ex)); });
}
throwerRejecter().catch(ex => console.log('caught ' + ex));
Finally, here are the last two nested combinations:
function rejecterThrower() {
return new Promise((resolve, reject) => { rejecter().catch(ex => { throw ex }); });
}
rejecterThrower().catch(ex => console.log('caught ' + ex));
Returns ERR_UNHANDLED_REJECTION and that looks sensible as rejection handling threw an exception.
And
function rejecterRejecter() {
return new Promise((resolve, reject) => { rejecter().catch(ex => reject(ex)); });
}
rejecterRejecter().catch(ex => console.log('caught ' + ex));
Prints caught rejected - a simple cascade of the rejection that is obvious.
Initially i was getting UnhandledPromiseRejectionWarning: TypeError: Cannot read property "distance" of undefined. to solve that error i have added a if condition with reject. now getting this 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: 1). Any solutions ?
here is my code
export function fun1(): Promise < survayResult > {
return new Promise((resolve, reject) => {
//..........
//..........
surveyDistance.forEach((result) => {
//
})
if(condition) {
reject(new Error("something went erong"));
return
}
let totalDistance = surveyDistance[0].distance;
// ...
//...
resolve("with some data");
})
}
I think you're over-thinking it, the promise should resolve or reject, they don't have built in error handling support. However in this case the error message is probably a good thing as it is telling you that the arguments (surveyDistance) are not what you expected. I won't comment on good or bad practices because I don't know your code base but you should hesitate to use try/catch unless there really is something that could go wrong (in my experience).
export function fun1(): Promise < survayResult > {
return new Promise((resolve, reject) => {
try {
//..........
//..........
surveyDistance.forEach((result) => {
//
})
if(condition) {
reject(new Error("something went erong"));
return
}
let totalDistance = surveyDistance[0].distance;
// ...
//...
resolve("with some data");
} catch (e) {
reject("Your error message:" + e);
}
})
}
const fetch = require('node-fetch');
let url = 'something.com';
module.exports = function(context) {
let a = fetch(url)
a.then(res => {
if(res.status!=200) throw new Error(res.statusText)
else{
context.done(null, res.body);
}
});
a.catch(err => {
console.log(err)
throw new Error(err)
});
};
I have a durable function that calls an activity function like above. I have set automatic retry on failure on this activity function. To retry the function needs to get an error.
So In get request I want to throw an error when i get response like 404 or something similar. But when i throw from catch block i get an error like below
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().
function pauses there and stops execution.I have to manually stop and start the execution. How can i handle this so that the function retries?
Your code branches.
Ignoring the detail, what you have is :
let a = <Promise>; // root
a.then(...); // branch_1
a.catch(...); // branch_2
So whereas you catch errors arising in a, any error arising in branch 1 will be uncaught. Hence the warning
Compare that with :
let a = <Promise>; // root
a.then(...).catch(...); // branch
or
<Promise>.then(...).catch(...); // no assignment necessary
So, you might write :
module.exports = function(context) {
return fetch(url)
.then(res => {
if(res.status!=200) {
throw new Error(res.statusText);
} else {
context.done(null, res.body);
}
})
.catch(err => {
console.log(err)
throw new Error(err)
});
};
Alternatively, depending on the required division of responsibilities between module and caller(s) ...
module.exports = function(context) {
return fetch(url)
.then(res => {
if(res.status!=200) {
throw new Error(res.statusText);
} else {
return res;
}
});
};
... and call .context.done(null, res.body); in a .then() callback in the caller.
In both cases, with return included, then the caller will need to catch errors otherwise you will again get an unhandled error warning.
Found that with the use of async/await this problem goes away and the function re-try after exception is thrown.
const fetch = require('node-fetch');
let url = 'something.com';
module.exports = async function(context) {
let res = await fetch(url)
if(res.status!=200) throw new Error(res.statusText);
else return res.body;
};
When I try to run this, i get "UnhandledPromiseRejectionWarning". But last "catch" received control anyway with correct "err" object.
I have got two warnings:
UnhandledPromiseRejectionWarning
PromiseRejectionHandledWarning
If I comment "return delay(5000);" all works fine.
Why does Node.JS handle "promiseErr" before I do that?
const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
let promiseErr = new Promise( (resolve, reject) => {
reject(new Error("__error__"));
});
let promiseOk = new Promise( (resolve, reject) => {
resolve();
});
promiseOk
.then( () => {
return delay(5000);
})
.then( () => {
return promiseErr;
})
.then( () => {
console.log("OK");
})
.catch( (err) => {
console.log(`ERR ${err}`);
});
program output
You have a rejected promise asynchronously (after 5000ms). Node.js detects unhandled promises by looking at promises that were not handled synchronously or within a microtick (inside a then).
Since Node.js cannot know "for sure" when a promise rejection is unhandled at the moment it errors on the safe side and gives you the warning. It is generally better to add catch handlers to promise errors synchronously as much as possible.
You can suppress the warning by adding a .catch(() => {}) to promiseErr when you create it which will handle the exception:
var promiseErr = ...
promiseErr.catch(() => {}); // add a catch handler without changing the original
In general - the solution is to not write code in such an error prone way. If promiseOk or delay rejects (which Node has no way of knowing) - then the exception in promiseErr itself is indeed unhandeld - so this is not really a safe way to write code.