Reputation: 23256
A module I am using is throwing an exception, that is going uncaught. Here is the snippet:
try {
mandrill_client.templates.info({ name: 'plaintexttemplates' }, (r, e) => {
console.log(e, 'e');
console.log(r, 'r');
});
} catch (e) {
console.log('From trycatch', e); // NEVER CAUGHT!!
}
Now when I run this, here is what happens:
/home/suhail/test/node_modules/mandrill-api/mandrill.js:114
throw {
^
Unknown_Template: No such template "plaintexttemplates"
This is indeed an unhandled exception (from the node module I am using). But why is my try/catch
not able to catch this?
To catch this exception I activated a listener:
process.on('uncaughtException', (err) => {
console.log('ERRRR', err); // WORKS FINE, OBVIOUSLY!!
});
It looks like my concepts are not right with exception handling. Could anyone tell me why the try/catch
is unable to catch the exception? Am I missing something?
I have not posted the module code here but have posted the references to the code functions below. This is the flow-control I saw during debugging.
Here are the subsequent methods that get called on calling mandrill_client.templates.info
.
The first method called is: Templates.prototype.info
The control passes to Mandrill.prototype.call
Finally the method that throws this error: Mandrill.prototype.onerror
PS: According to the documentation:
The throw statement throws a user-defined exception. Execution of the current function will stop (the statements after throw won't be executed), and control will be passed to the first catch block in the call stack
. If no catch block exists among caller functions, the program will terminate.
But this is not happening!
Upvotes: 1
Views: 1781
Reputation: 707436
If the library is throwing asynchronously, that's a problem. You can't fix that any way other than editing the library. Bad library, bad library.
An asynchronous function starts the async operation, then returns and your code continues to execute until the call stack is clear (and any exception handlers of yours are gone). Then, sometime later, the async operation triggers a callback (with a clean call stack) and, if it throws an exception there, there is none of your code in the call stack to catch it. It is the responsibility of the library to catch its own async exceptions and communicate them back to the caller in a documented way - usually via an error parameter in the callback (like you see with all async operations in the standard nodejs libraries).
Here's an example to illustrate:
function delay(t, callback) {
setTimeout(function() {
throw new Error("try to catch me");
callback(); // won't get here
}, t);
}
try {
delay(100, function() {
console.log("won't get here");
});
} catch(e) {
console.log("won't find any exception here");
}
console.log("will get here before the exception is thrown");
// exception will be thrown sometime later with a clean callstack so
// the above try/catch is no longer in place
The proper way to handle this is for the async operation to catch it's own exceptions and communicate them back via the callback:
function delay(t, callback) {
setTimeout(function() {
// async operation catches its own exceptions
try {
throw new Error("try to catch me");
callback(null); // won't get here
} catch(e) {
callback(e);
}
}, t);
}
delay(100, function(err) {
if (err) {
console.log(err);
} else {
console.log("got here with no error");
}
});
console.log("will get here before the exception is thrown");
Upvotes: 1
Reputation: 1955
The reason is the function you are executing in try...catch
block handles error using a callback and is probably doing some asynchronous task before invoking the callback. Javascript try...catch
only works for synchronous/blocking tasks.
Upvotes: 1