Programmers create errors, programs create errors, hardware creates errors, networks create errors.
These would be things like:
These errors could halt the program altogether and can occur before the program even starts. Sometimes as part of the page load or Node startup, you’ll see these errors thrown, preventing the program from starting.
These are usually the easiest to fix because they give you a specific line of code and specific error messages. Some IDEs can even detect these errors as you type them out.
The next group of errors is what we call system errors. We could describe them as runtime operating system issues because we can’t possibly predict that all these will occur until after the program starts running. Issues like:
- File doesn’t exist
- Folder doesn’t exist
- Permission issues
- Network issues
- Hardware issues
- General system constraints
They relate to things dynamic that can occur right while the code is running. Usually, you can catch them and send out useful error messages to the user.
Suppose that the user’s internet disconnects midway through your program’s attempt to retrieve the latest data — you can handle that error and inform the user that they should check their system for internet access.
The next classification for errors is user-specified, which are created by the engineers who authored the code. These are engineer-derived errors that are typically business-specific:
- Invalid authentication
- Invalid authorization
- Data validation
- Option validation
- Security breach detection
Any kind of error message that an engineer decides to add to their application becomes a user-defined error. You should use them — I use them a lot. Check out some examples:
throw new Error('Invalid Authentication');
throw new Error('Invalid Username - Too Short');throw new Error('Invalid Ice Cream Flavor');
The last group of error types is assertions, a very special group. These are kind of similar to engineer-derived issues, but instead, engineers are passing information, like implementation messages from the author engineer to a future engineer:
- Check preconditions to catch mistakes in development or runtime
- Typically removed from production builds of an application
- Useful for “design by contract”
They usually check something like a precondition and catch mistakes during development or runtime. Another common and way to solve this problem is a unit test.
The statement(s) to be executed. You expect that errors may occur.
The statement(s) to be executed if an exception is thrown. You can handle errors and react to the issue — try not to throw more errors here!
The statements to execute after the try and catch block complete, regardless of branch. You can do follow-up work after either trying or catching.
Error Handling Basics
What do we do once we get inside a catch block?
Catch -> Triage -> Log
When your JS code catches expected errors after they occur, the can handle them accordingly. Here are a couple of options to consider.
Once the error is caught, the code can determine the error types (see above) and severity.
If you do catch an error, you want to determine what error it was, and the severity of it.
It could be a true fatal error where your application can no longer run properly, or it could be a warning.
If the user is not authenticated, the application may not need to crash, it just means the app has to make the user login. They can try again.
If the server’s down, there’s nothing the user can do to solve the problem. The app can just display a message like:
We’re sorry, we’re experiencing difficulties.
3. Beacon or Track
A great additional is to send a beacon to an external error tracking system (Rollbar, Sentry, Bugsnag, etc). This is useful because it can provide deeper insight and also notify your team via email, Slack, text, or other means.
Either way, you want to make sure you send your errors somewhere so that the application developers are aware of them and can fix them.