Last updated: 05/05/2018
This post summarizes and curates most of the knowledge gathered to date on Node error handling. It contains more than 35 quotes, code examples and diagrams from the highest ranked blog posts and StackOverflow threads.
Don’t miss out: nearby each best practice a “GIST Popup” icon appears, clicking on it will show further explanation, selected blog quotes and code examples
Written by Yoni Goldberg – An independent Node.JS consultant who provide Node consulting and training. See also my GitHub with over 70+ best practices
1. Use Async-Await or promises for async error handlingSummarizes and quotes 5 sources, click on THE GIST below to see TL;DR: Handling async errors in callback style is probably the fastest way to hell (a.k.a the pyramid of doom). The best gift you can give to your code is using instead a reputable promise library or async-await which provides much compact and familiar code syntax like try-catch Otherwise: Node.JS callback style, function(err, response), is a promising way to un-maintainable code due to the mix of error handling with casual code, excessive nesting and awkward coding patterns THE GIST popup: click here for quick examples, quotes and code examples |
|
2. Use only the built-in Error objectSummarizes and quotes 5 sources TL;DR: Many throws errors as a string or as some custom type – this complicates the error handling logic and the interoperability between modules. Whether you reject a promise, throw exception or emit error – using only the built-in Error object will increases uniformity and prevents loss of information Otherwise: When invoking some component, being uncertain which type of errors come in return – makes it much harder to handle errors properly. Even worth, using custom types to describe errors might lead to loss of critical error information like the stack trace! THE GIST popup: click here for quick examples, quotes and code examples |
|
3. Distinguish operational vs programmer errorsSummarizes and quotes 3 sources TL;DR: Operational errors (e.g. API received an invalid input) refer to known cases where the error impact is fully understood and can be handled thoughtfully. On the other hand, programmer error (e.g. trying to read undefined variable) refers to unknown code failures that dictate to gracefully restart the application Otherwise: You may always restart the application when an error appear, but why letting ~5000 online users down because of a minor, predicted, operational error? the opposite is also not ideal – keeping the application up when unknown issue (programmer error) occurred might lead to an unpredicted behavior. Differentiating the two allows acting tactfully and applying a balanced approach based on the given context THE GIST popup: click here for quick examples, quotes and code examples |
|
4. Handle errors centrally, through but not within middlewareSummarizes and quotes 4 sources TL;DR: Error handling logic such as mail to admin and logging should be encapsulated in a dedicated and centralized object that all end-points (e.g. Express middleware, cron jobs, unit-testing) call when an error comes in. Otherwise: Not handling errors within a single place will lead to code duplication and probably to errors that are handled improperly THE GIST popup: click here for quick examples, quotes and code examples |
|
|
|
5. Document API errors using SwaggerSummarizes and quotes 1 source TL;DR: Let your API callers know which errors might come in return so they can handle these thoughtfully without crashing. This is usually done with REST API documentation frameworks like Swagger Otherwise: An API client might decide to crash and restart only because he received back an error he couldn’t understand. Note: the caller of your API might be you (very typical in a microservices environment) THE GIST popup: click here for quick examples, quotes and code examples |
|
6. Shut the process gracefully when a stranger comes to townSummarizes and quotes 4 sources TL;DR: When an unknown error occurs (a developer error, see best practice number #3)- there is uncertainty about the application healthiness. A common practice suggests restarting the process carefully using a ‘restarter’ tool like Forever and PM2 Otherwise: When an unfamiliar exception is caught, some object might be in a faulty state (e.g an event emitter which is used globally and not firing events anymore due to some internal failure) and all future requests might fail or behave crazily THE GIST popup: click here for quick examples, quotes and code examples |
|
7. Use a mature logger to increase errors visibilitySummarizes and quotes 2 sources TL;DR: A set of mature logging tools like Winston, Bunyan or Log4J, will speed-up error discovery and understanding. So forget about console.log. Otherwise: Skimming through console.logs or manually through messy text file without querying tools or a decent log viewer might keep you busy at work until late THE GIST popup: click here for quick examples, quotes and code examples |
|
8. Test error flows using your favorite test frameworkSummarizes and quotes 1 source TL;DR: Whether professional automated QA or plain manual developer testing – Ensure that your code not only satisfies positive scenario but also handle and return the right errors. Testing framework like Mocha & Chai can handle this easily (see code examples within the “Gist popup”) Otherwise: Without testing, whether automatically or manually, you can’t rely on our code to return the right errors. Without meaningful errors – there’s no error handling THE GIST popup: click here for quick examples, quotes and code examples |
|
9. Discover errors and downtime using APM productsSummarizes and quotes 2 sources TL;DR: Monitoring and performance products (a.k.a APM) proactively gauge your codebase or API so they can auto-magically highlight errors, crashes and slow parts that you were missing Otherwise: You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which are your slowest code parts under real world scenario and how these affects the UX THE GIST popup: click here for quick examples, quotes and code examples |
|
10. Catch unhandled promise rejectionsSummarizes and quotes 2 sources TL;DR: Any exception thrown within a promise will get swallowed and discarded unless a developer didn’t forget to explictly handle. Even if you’re code is subscribed to process.uncaughtException! Overcome this by registering to the event process.unhandledRejection Otherwise: Your errors will get swallowed and leave no trace. Nothing to worry about THE GIST popup: click here for quick examples, quotes and code examples |
|
11. Fail fast, validate arguments using a dedicated librarySummarizes and quotes 2 sources TL;DR: This should be part of your Express best practices – Assert API input to avoid nasty bugs that are much harder to track later. Validation code is usually tedious unless using a very cool helper libraries like Joi Otherwise: Consider this – your function expects a numeric argument “Discount” which the caller forgets to pass, later on your code checks if Discount!=0 (amount of allowed discount is greater than zero), then it will allow the user to enjoy a discount. OMG, what a nasty bug. Can you see it? THE GIST popup: click here for quick examples, quotes and code examples |
|
12. [Deprecated]Use Node.jS domain to isolate errorsThis feature is now officially deprecated TL;DR Domains allow to catch exceptions from any source within a certain code path. This is great for isolating errors between users/requests (like PHP and .NET) or error of a certain module. However they are now officially deprecated thus should not used in new projects |
|
13. Wait, more best practices are comingStay tuned for more TL;DR: This post is being updated frequently with new best practices and updates. Have any improvement suggestion or corrections? you are more than welcome to suggest these within the comments below Otherwise: You’ll miss useful best practices and tips |
-
Rob s.
-
stasgit
-
Eitan Rivlin
-
ilyaigpetrov
-
Josh Noe
-
-
Vu Le
-
Vu Le
-
Alejandro Oviedo
-
Christophe Ferauge
-
Yoni Goldberg
-
-
German Torvert
-
Yoni Goldberg
-
-
Andrew Dalgleish
-
Yoni Goldberg
-
-
Vinicius Tabille
-
Yoni Goldberg
-
Vinicius Tabille
-
Yoni Goldberg
-
-
-
-
Josh Noe
-
Caio Cutrim