Exception in subscription terminates Observable in Angular but not in Node - node.js

I have this example code sequence that I either run in Angular or in a node app. Behavior is different, and I would like to know why.
of(1, 2, 3, 4).subscribe((x) => {
console.log(`x: ${x}`);
if (x === 2) {
throw new Error('xxx');
}
});
When executing in node all four numbers are written to the console. Exception is shown afterwards.
When executing in Angular, e.g. in any ngOnInit(), it only logs 1 and 2 and then the Observable is terminated. The consequence is that any exception in a subscription block breaks the program.
Is there any description of why and how this difference in behavior.
Addendum: Reading more on the subject, the Angular (or more general the browser) behavior is what is to be expected. It is really the node.js behavior that is surprising. Why does the node.js program not stop after two digits?

From the comments section, you are actually trying to figure out the difference in behavior between the rxjs v6 and v7 in terms of handling the consumer thrown unhandled errors.
In general throwing errors from the observers is a bad idea as it will lead to blocking of the observables if shared between multiple observers. This problem is handled in the v6 by improving the error handling mechanism as mentioned here SafeSubscriber and more specifically in next. Below snapshot of the next
next(value?: T): void {
if (!this.isStopped && this._next) {
const { _parentSubscriber } = this;
if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
this.__tryOrUnsub(this._next, value);
} else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) {
this.unsubscribe();
}
}
}
If you see from the above snapshot when an unhandled error is thrown from the observer the code is trying to subscribe and then if error it is unsubscribing the observable in __tryOrUnsub. Finally the error is added to call stack and thrown once the call stack is empty from method hostReportError(once all the observers complete asynchronously). Below is the sample stackblitz to demonstrate the same.
https://stackblitz.com/edit/angular-ivy-v7dojh?file=src%2Fapp%2Fhello.component.ts
This logic further changed in v7 as mentioned by the this commit. The unsubscribing logic is removed and the asynchronous error call stack is maintained as shown below sample stackblitz, due to which the all the 4 elements are printed and the error is printed to console once the call stack is empty asynchronously usning reportUnhandledError -
https://stackblitz.com/edit/angular-ivy-p8zj2k?file=src%2Fapp%2Fhello.component.ts

Related

RxJava: UndeliverableException when flatMap combined with switchMap

TL;DR
I think that flatMap combined with switchMap might not terminate the stream correctly, thus UndeliverableException happens. How can I fix this?
The Structure
I'm making a little bit complex stream -- combined with flatMap and switchMap -- like below, in RxKotlin (RxJava 3):
someObservable
.flatMapMaybe {
if (matchCondition(it)) Maybe.just(it)
else Maybe.never()
}.flatMapSingle {
procedureMiddle(it) // Inconsistent-time-consuming Single
}.switchMap {
procedureLater(it)
}.doOnError {
dealWithError(e)
}.retry()
.subscribeBy(
// ...
)
The procedureMiddle inside flatMapSingle has a chance of returning Error in the end.
The Exception
It turns out that sometimes the error from procedureMiddle might jump out of structure, not being ignored by retry, nor dealt in dealWithError in doOnError:
W/System.err: io.reactivex.rxjava3.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | my.custom.app.CustomException
// traces indicates that the Exception is thrown from inside procedureMiddle
The Question
In fact the UndeliverableException doesn't really cause crash, but it's a little bit annoying for me --especially it looks like a situation I need to handle. However I thought the structure is correctly written? So here's my question:
Does switchMap really (correctly) terminate the last stream from flatMap? (And can be used to prevent UndeliverableException?)
If so, at which part of code I should adjust? If not so, how could I prevent the exceptions along with my structure? (I want to concat procedureLater after procedureMiddle, and keep only latest one)
Any suggestion or explanation would be helpful.
The RxJava2 Official Doc explains a few about UndeliverableException:
UndeliverableException: wraps the original exception that can't be delivered due to lifecycle restrictions on a Subscriber / Observer.
So it, actually, does NOT mean that your code have any problems (directly). It just reminds you that some streams still throw error after you ended/canceled/disposed them.
About the question:
Does switchMap really (correctly) terminate the last stream from flatMap? (And can be used to prevent UndeliverableException?)
Yes, it terminates the last stream.
And NO. UndeliverableException would still happen. Because it terminates the last stream, so if the last stream throws error, the error would be wrapped and thrown as UndeliverableException.
If so, at which part of code I should adjust? If not so, how could I prevent the exceptions along with my structure?
You don't need to adjust the code, nor preventing UndeliverableException, as it always have a chance to come up when disposing/cancelling/ending any streams (manually or even automatically.)
I suggest just ignoring it:
RxJavaPlugins.setErrorHandler {
if (it is UndeliverableException) {
// This happens when throwable comes out AFTER subscription is canceled or disposed.
// Not what we care about as it is likely disposed by user or system.
Log.d(
"Application", "UndeliverableException: ignored.\n" +
"$it: problem ${it.cause} / ${it.cause?.message}\n" +
"at ${it.cause?.stackTraceToString()}"
)
return#setErrorHandler
}
// other Exceptions: do some report
}

Node.js When updating a document failed, is best to throw an exception or returning information?

I have an updateDocument method in a class for a service layer in a node.js, express, mongoose application. I'm wondering what is the best practice for handing cases where the update method didn't update a document, for example if the wrong id is passed in.
Version 1: If the update wasn't successful, return an object with success: false:
async updateDocument(id, updates) {
const output = await this.DocumentModel.updateOne({ _id: id }, updates);
let message = 'Something went wrong';
let success = false;
let updatedItem = null;
if (output.nModified) {
message = 'Successfully updated document.';
success = true;
updatedItem = await this.getDocument(id);
}
return { message, success, updatedItem};
}
Version 2: If the update wasn't successful, throw an error:
async updateDocument(id, updates) {
const output = await this.DocumentModel.updateOne({ _id: id }, updates);
let updatedItem;
if (output.nModified) {
updatedItem = await this.getDocument(id);
} else{
throw new Error("The document wasn't updated")
}
return updatedItem;
}
Do you always throw an exception when the input, such as a bad id, isn't correct? Or could you return information about the update being a success or not? As newbie node.js developer, I'm not sure I am grasping the full picture enough to recognize problems with either method.
There is no golden way, only principles that lead to robust and well-maintainable software.
Generally, you should use a try-catch-statement for all kinds of errors that are not in your control (connections, disk space, credentials, ...) . The errors should then be handled as soon as possible, but not before. The reason for this is that you often don't know, yet, how to handle an error in an appropriate manner at a lower layer.
For logical "errors" that you can expect (wrong input format, missing username, unknown options, ...), you should use an if-statement or a validation function and then throw an error, if anything is not as expected.
In your case, you should check, if the methods updateOne or getDocument can throw errors. If yes, you should wrap these functions with a try-catch-statement.
A few more tips:
Both versions of your code are good. But I would prefer version 2 because it is more concise.
If you are sure that there is always an output object, you can destruct the nModified property like this:
const { nModified } = await this.DocumentModel.updateOne({ _id: id }, updates);
If you use a negative if-statement, you can reduce the depth of indentation and you can use const variables:
if (!nModified) {
throw new Error("The document wasn't updated")
}
const updatedItem = await this.getDocument(id);
Now, you could also directly return this.getDocument(id) and don't need the variable updatedItem anymore.
You can finally handle your errors in your controller classes.
You can use custom error classes to be consistent in your error handling and error messages all over your app.
I hope this is at least a bit helpful.
References
These are some similar questions with good answers. But you need to take care because many code examples are not in modern JavaScript.
A general discussion about the pros and cons of Error-Handling vs.
if-else-statements is done here:
What is the advantage of using try {} catch {} versus if {} else {}
Error-Handling in Node.js is discussed here in this thread:
Node.js Best Practice Exception Handling
It seemed like there were a lot of different opinions on this and not one go-to method. Here's some information I found and what I ended up doing.
When to throw an exception?
Every function asks a question. If the input it is given makes that question a fallacy, then throw an exception. This line is harder to draw with functions that return void, but the bottom line is: if the function's assumptions about its inputs are violated, it should throw an exception instead of returning normally.
Should a retrieval method return 'null' or throw an exception when it can't produce the return value?
Answer 1:
Whatever you do, make sure you document it. I think this point is more important than exactly which approach is "best".
Answer 2:
If you are always expecting to find a value then throw the exception if it is missing. The exception would mean that there was a problem.
If the value can be missing or present and both are valid for the application logic then return a null.
More important: What do you do other places in the code? Consistency is important.
Where should exceptions be handled?
Answer 1: in the layer of code that can actually do something about the error
Exceptions should be handled in the layer of code that can actually do something about the error.
The "log and rethrow" pattern is often considered an antipattern (for exactly the reason you mentioned, leads to a lot of duplicate code and doesn't really help you do anything practical.)
The point of an exception is that it is "not expected". If the layer of code you are working in can't do something reasonable to continue successful processing when the error happens, just let it bubble up.
If the layer of code you are working in can do something to continue when the error happens, that is the spot to handle the error. (And returning a "failed" http response code counts as a way to "continue processing". You are saving the program from crashing.)
-source: softwareengineering.stackexchange
Answer 2: Handle errors centrally, not within a middleware
Without one dedicated object for error handling, greater are the chances of important errors hiding under the radar due to improper handling. The error handler object is responsible for making the error visible, for example by writing to a well-formatted logger, sending events to some monitoring product like Sentry, Rollbar, or Raygun. Most web frameworks, like Express, provide an error handling middleware mechanism. A typical error handling flow might be: Some module throws an error -> API router catches the error -> it propagates the error to the middleware (e.g. Express, KOA) who is responsible for catching errors -> a centralized error handler is called -> the middleware is being told whether this error is an untrusted error (not operational) so it can restart the app gracefully. Note that it’s a common, yet wrong, practice to handle errors within Express middleware – doing so will not cover errors that are thrown in non-web interfaces.
-source; Handle errors centrally, not within a middleware
More: Best Practice Node.js: Error Handling
So it seems like these two principles disagree. #1 says to handle it right away if you can. So for me it would be in the service layer. But the #2 says handle it centrally, like in the server file. I went with #2.
My decision: throw the error in a custom error class
It combined a few methods people suggested. I am throwing the error, but I'm not "log and rethrow"-ing, as the answer above warned against. Instead, I put the error in a custom error with more information and throw that. It is logged and handled centrally.
So first in my service layer this is how an error is thrown:
async addUser(user) {
let newUser;
try {
newUser = await this.UserModel.create(user);
} catch (err) {
throw new ApplicationError( // custom error
{
user, // params that are useful
err, //original error
},
`Unable to create user: ${err.name}: ${err.message}` // error message
);
}
return newUser;
}
ApplicationError is a custom error class that takes an info object and a message. I got this idea from here:
In this pattern, we would start our application with an ApplicationError class this way we know all errors in our applications that we explicitly throw are going to inherit from it. So we would start off with the following error classes:
-source: smashingmagazine
You could put other helpful information in your custom error class, even maybe what EJS template to use! So you could really handle the error creatively depending on how you structure your custom error class. I don't know if that's "normal", maybe it's not SOLID to include the EJS template, but I think it's an interesting concept to explore. You could think about other ways that might be more SOLID to dynamically react to errors.
This is the handleError file for now, but I will probably change it up to work with the custom error to create a more informative page. :
const logger = require("./logger");
module.exports = (err, req, res, next) => {
if (res.headersSent) {
return next(err);
}
logger.log("Error:", err);
return res.status(500).render("500", {
title: "500",
});
};
Then I add that function to my server file as the last middleware:
app.use(handleError);
In conclusion, it seems like there's a bit of disagreement on how to handle errors though it seems more people think you should throw the error and probably handle it centrally. Find a way that works for you, be consistent, and document it.

UWP Windows 10 app crashes in release mode but works fine in debug mode

My UWP app is crashing in Release mode and works fine in Debug mode but I can't put my finger on what the issue is but I know it's related to a combination of raising an event from System.Threading.Timer and MVVMLight.
I created an new dummy application and use the same code (ZXing.net.mobile where I used 2 portable libraries and I used my own user control which is a simplified version of theirs - I'm using events instead of <Action>). This works fine and I'm currently trying to put more steps into it i.e. include mvvmlight and navigation but so far, I can't reproduce the problem in this dummy app.
The error I'm getting is:
Unhandled exception at 0x58C1AF0B (mrt100_app.dll) in Company.MyApp.App.exe:
0xC0000602: A fail fast exception occurred. Exception handlers will not be
invoked and the process will be terminated immediately.
Followed by:
Unhandled exception at 0x0107D201 (SharedLibrary.dll) in
Company.MyApp.App.exe: 0x00001007.
When looking at the Threads window, one of the worker thread has the following information if that's of help.
Not Flagged > 4012 0 Worker Thread <No Name>
System.Private.Interop.dll!System.Runtime.InteropServices.
ExceptionHelpers.ReportUnhandledError Normal
[External Code]
System.Private.Interop.dll!System.Runtime.InteropServices.ExceptionHelpers.
ReportUnhandledError(System.Exception e) Line 885
System.Private.Interop.dll!Internal.Interop.InteropCallbacks.ReportUnhandledError
(System.Exception ex) Line 17
System.Private.WinRTInterop.CoreLib.dll!Internal.WinRT.Interop.WinRTCallbacks.
ReportUnhandledError(System.Exception ex) Line 274
System.Private.CoreLib.dll!System.RuntimeExceptionHelpers.ReportUnhandledException
(System.Exception exception) Line 152
System.Private.Threading.dll!System.Threading.Tasks.AwaitTaskContinuation.
ThrowAsyncIfNecessary(System.Exception exc) Line 784
System.Private.Threading.dll!System.Threading.WinRTSynchronizationContext.Invoker.
InvokeCore() Line 182
System.Private.Threading.dll!System.Threading.WinRTSynchronizationContext.Invoker.
Invoke(object thisObj) Line 162
System.Private.CoreLib.dll!System.Action<System.__Canon>.
InvokeOpenStaticThunk(System.__Canon obj)
System.Private.WinRTInterop.CoreLib.dll!Internal.WinRT.Interop.WinRTCallbacks.PostToCoreDispatcher.AnonymousMethod__0() Line 266
MyCompany.MyApp.App.exe
MyCompany.MyApp.App.ViewModels.ValidateHandler.Invoke(string pin)
MyCompany.MyApp.App.McgInterop.dll!McgInterop.ReverseComSharedStubs
.Proc_(object __this, System.IntPtr __methodPtr) Line 6163
MyCompany.MyApp.App.McgInterop.dll!Windows.UI.Core.DispatchedHandler__Impl.Vtbl.Invoke__STUB(System.IntPtr pComThis) Line 45147
[External Code]
Within my QR Code UserControl, it's using a System.Threading.Timer and it raises an event when a QR Code is found:
timerPreview = new Timer(async (state) =>
{
....
// Check if a result was found
if (result != null && !string.IsNullOrEmpty(result.Text))
{
Debug.WriteLine("Barcode Found: " + result.Text);
if (!this.ContinuousScanning)
{
delay = Timeout.Infinite;
await StopScanningAsync();
}
else
{
delay = this.ScanningOptions.DelayBetweenContinuousScans;
}
OnBarcodeFound(result.Text);
}
timerPreview.Change(delay, Timeout.Infinite);
}, null,
this.ScanningOptions.InitialDelayBeforeAnalyzingFrames,
Timeout.Infinite);
In the page that host the QRCode UserControl, I've got the following code:
private async void ScannerControl_BarcodeFound(string barcodeValue)
{
var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => {
Debug.WriteLine(barcodeValue);
GetViewModel.BarcodeFound(barcodeValue);
});
}
As you can see, I'm passing the QrCode value to my ViewModel and from there, I sent a message and then re-direct to another page:
public void BarcodeFound(string barcodeData)
{
Messenger.Default.Send<string>(barcodeData, MessengerTokens.QrCodeFound);
this.NavigationFacade.NavigateToMyOtherPage();
}
I could keep going and provide additional code, but as I add additional breakpoints I can see that the code and passing the correct value and going to the correct location but eventually it throws this error. If I add additional error handlers or dispatcher code, it eventually works and goes to the next page as expected but when I click on a button in my CommandBar, it then takes a while and it eventually throws the same error, so by adding these additional bits of code, I feel I'm just pushing down the problem further down the line.
Anyone got any suggestions on how I get around this problem. I wish I could share the full app but definitely can't. So I know it will be hard to provide a solution, but if anyone has suggestions I'd appreciate them.
As I said, I think the issue is a result of a combination of threading and mvvmlight but it's driving me nuts that my test app so far is working exactly as expected, so I'm pretty sure it's not Zxing or my UserControl.
Any help, suggestions would be greatly appreciated or if you need me to provide additional info, please let me know what and I'll try to provide it.
Thanks.
Well, this was a painstaking exercise and a huge waste of my time!
It was down to a few things!!
I was using a different DataService in Releasemode which wasn't implemented. By implemented, I mean all my functions were returning the NotImplementedException or null values.
When passing my model to my ViewModel, I did not check if it was null, thus causing unhandled exceptions.
I had a chain of mvvmlight events (Messenger.Default.Send<>) being triggered and none were checking for error or null values.
While all of these were caused by poor validation from my part, these errors are extremely poorly reported in Release mode! if from the get go, I had received a NullReferenceException or any kind of exceptions, it would have put me in the right direction immediately, but throwing errors such as the one I've had were totally useless but it didn't but lesson learned!!
All I can say is that if this problem ever happens to you, don't waste your time rewriting code or trying to find workarounds. First work your way through your workflow/chain of events and hopefully, you'll eventually catch the culprit.
Hope this helps.
Sadly we were facing a similar issue, ours was involved with setting the qualifier values for changing localization on the fly in the app but came up with mystery fail fast/SharedLibrary native errors. Upgrading the Microsoft.NETCore.UniversalWindowPlatform package from 6.0.4 to 6.0.7 seems to have resolved the issue.
Only thought of this because another place I was researching this error involved someone solving a SharedLibrary problem by upgrading their NETCore package, that case was an earlier one (5.x), but figured it was worth a shot.

Handling errors at a global level

I am trying to understand how to build my error handling system for my api.
Let's say I have a the following line in a controller method :
var age = json.info.age;
with
json = {"id":1, "name":"John", info": {"age":27, "sex":"m"}}
Let's say that the object doesn't contain an info field, I'll get the following error TypeError: Cannot read property 'info' of undefined and my server will crash.
Is there a way to make a higher level abstraction and catch all the potential errors that I could have? Or should I have a try/catch system for each of the methods of my controllers?
BEWARE OF THE CODE BELOW, IT WILL BITE YOU WHENEVER IT CAN!
Don't use the code snippet below if you do not understand its
implications, please read the whole answer.
You can use the node way for uncaught errors. Add this in your config/bootstrap.js
Updated the snippet below to add what was said in the comments, also added a warning about using a global to respond to the user.
process.on('uncaughtException', function (err) {
// Handle your errors here
// global.__current__ is added via middleware
// Be aware that this is a bad practice,
// global.__current__ being a global, can change
// without advice, so you might end responding with
// serverError() to a different request than the one
// that originated the error if this one happened async
global.__current__.res.serverError();
})
Now, can doesn't mean should. It really depends on your needs, but do not try to catch BUGS in your code, try to catch at a controller level the issues that might not happen every time but are somehow expected, like a third-party service that responded with empty data, you should handle that in your controller. The uncaughtException is mainly for logging purposes, its better to let your app crash if there is a bug. Or you can do something more complicated (that might be better IMHO), which is to stop receiving requests, respond to the error 500 (or a custom one) to user that requested the faulty endpoint, and try to complete the other requests that do not relate to that controller, then log and shutdown the server. You will need several instances of sails running to avoid zero downtime, but that is material for another question. What you asked is how to get uncaught exceptions at a higher lvl than the controllers.
I suggest you read the node guide for error handling
Also read about domains, even thought they are deprecated you can use them, but you would have to deal with them per controller action, since sails does not provide any help with that.
I hope it helps.
You can check this way if you want to:
if (object != null && object.response != null && object.response.docs != null){
//Do your stuff here with your document
}
I don't really get what is your "object" variable in the first place, so i don't know if you can check it at a different level, is it a sails parameter to your controller ?
So that's how I did it, thanks to Zagen's answer.
module.exports.bootstrap = function(cb) {
process.on('uncaughtException', function (err) {
//Handle your errors here
logger.fatal(err);
global.__current__.res.serverError();
})
cb();
};
I send a generic error 500 to the user if any uncaught exception is thrown, and I log the error to the fatal level. On that way, my server is still accessible 24/7 and I can monitor the logs at another level and trigger an alarm on a fatal error. I can then fix the exception that was thrown.

Handling exceptions in express

I'm having trouble understanding how to handle something that it seems like would be a pretty basic aspect of express. If I have some code that throws an exception in an async callback, there is no way I can catch that exception because the try/catch block is no longer in scope by the time the callback is running. In these scenarios the browser will hang until it eventually give up stating that the server is unresponsive. This is a very bad user experience. I would much rather be able to immediately return a 500 error to the client. The default express error handler apparently does not handle this situation. Here is some sample code:
var express = require("express");
var app = express();
app.use(app.router);
//express error handler (never called)
app.use(function(err, req, res, next) {
console.log(err);
res.send(500);
});
app.get("/test", function(req, res, next) {
require("fs").readFile("/some/file", function(err, data) {
a.b(); //blow up
});
});
app.listen(8888);
In the above code, the line a.b() throws a "ReferenceError: a is not defined" exception. The defined error handler is never called. Notice that the err object returned by fs.readFile() is null in this case because the file was correctly read. The bug is the code inside the async handler.
I have read this post about using node's uncaughtExpception even, but the documentation says not use that method. Even if I did use it, how would I then send the 500 response back to the user? The express response object is no longer around for me to use.
So how do you handle this scenario?
OK, I'm just going to post an entirely different answer since my first answer has some valuable information but is off topic in hindsight.
The short answer: the correct thing to do is what already happens: your program should print a stack trace and exit with an error.
The underlying thinking:
So I think you need to think about errors in different categories. My first answer deals with data-related errors that a well-written program can and should handle cleanly. What you are describing is a CRASH. If you read the node.js documentation you linked to, it is correct. The only useful thing your program can do at this point is exit with a stack trace and allow a process supervisor to restart it and attain an understood state. Once your program has crashed, it is essentially unrecoverable due to the extremely wide range of errors that could be the root cause of an exception getting to the top of the stack. In your specific example, this error is just going to continue happening every time until the source code bug is fixed and the application is redeployed. If you are worried that untested and buggy code is going to get into your application, adding more untested and buggy error handling code isn't really addressing the right problem.
But in short, no, there's no way to get a reference to the HTTP request object that caused this exception so AFAIK you cannot change the way this is perceived by the end user in the browser, outside of handling this at an intermediate reverse proxy layer where you could configure a crude timeout and send a more friendly error page (which of course would be useless for any request that isn't for a full HTML document).
The Bible of Error Handling in Node
Error Handling in Node.js by Dave Pacheco is the definitive work on this topic in my opinion. It is comprehensive, extensive, and thorough. I recommend reading and re-reading periodically.
To address #asparagino's comments, if an unhandled exception is easily reproducible or happening with high frequency, it's not an edge case, it's a bug. The correct thing to do is improve your code to not generate uncaught exceptions in face of this situation. Actually handle the condition, thus converting a programmer error into an operational error, and your program can continue without a restart and without an uncaught exception.
You should use express's error handling middleware via app.use(error, req, res, next). Express maintains a separate middleware stack that it uses when the normal middleware stack throws an uncaught exception. (Side note that express just looks at the callback's arity (number of expected arguments) to categorize it as regular middleware or error handling middleware, which is a bit magical, so just keep in mind you must declare the arguments as above for express to understand this is an error handling middleware).
And based on your question and comments, just understand that exceptions aren't all that useful in node.js because every async call gets a new stack, which is why callbacks are used everywhere and the 1st argument is an error universally. Your try/catch block in the example is only going to catch an exception thrown directly by findById (like if id were undefined, as it is in your snippet), but once an actual call to the database is made, that's it, the call stack is over and no further exceptions can happen until a totally different call stack starts when node invokes the async IO callback.
Thanks for the answer, but this only works if I put the try/catch inside the async callback and have the catch do next(exp). I'd like to avoid having separate try/catch blocks in every single async callback.
Nope, that's not true. You don't have to manually call next(exp). Express will catch the error and trigger the error handling middleware for you (that's how express does it's developer-friendly exception report pages in dev mode anyway). And async libraries don't throw exceptions even under "normal" error conditions. They pass an error to the callback, so in general you don't have to bother with try/catch that much in node. Just never ignore an error parameter passed to a callback function, and you're fine.
You don't see this boilerplate in node:
someDb.query(someCriteria, function (error, result) {
try {
//some code to deal with result
} catch (exception) {
callback(exception);
}
});
You do see this though:
someDb.query(someCriteria, function (error, result) {
if (error) {
callback(error);
return;
}
//some code to deal with result
});
Node handles IO differently, which means the call stack works differently, which means exceptions work differently, which means error handling works differently. You can write a stable node/express app that handles errors without crashing without writing a single try/catch. (express has one that handles uncaught errors that bubble all the way to the top). It's not a functional limitation, it's just a consquence of async IO that means you have to write your code differently and handle errors with callbacks instead of exceptions. Thinking of it as a "limitation" as opposed to the "way it is" is putting a negative connotation on something that is really just a technical reality. There are clean and robust patterns for exception handling in both a synchronous and asynchronous paradigm.

Resources