Error handling is one of those topics developers often ignore until production starts failing.
A good error-handling strategy makes an application easier to debug, monitor, and maintain.
The Problem With Random try/catch Blocks
You might see code like:
try {
await doSomething();
} catch (error) {
console.log(error);
}
Enter fullscreen mode Exit fullscreen mode
This prevents an immediate crash, but it doesn’t necessarily solve the problem.
What should happen next?
Should the API return 500?
Should the error be logged?
Should the request be retried?
Should the user receive a friendly message?
Centralized Error Handling
Express applications can use centralized middleware:
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({
message: "Something went wrong"
});
});
Enter fullscreen mode Exit fullscreen mode
Application code can then pass errors to the middleware.
Separate Operational and Programming Errors
Not every error means the same thing.
An invalid request:
400 Bad Request
Enter fullscreen mode Exit fullscreen mode
is very different from:
Database connection unexpectedly failed
Enter fullscreen mode Exit fullscreen mode
The first may be expected.
The second might require immediate investigation.
Don’t Leak Sensitive Information
Avoid returning:
{
"error": "MongoServerError: password authentication failed..."
}
Enter fullscreen mode Exit fullscreen mode
to users.
Internal details belong in secure logs.
Users generally need a useful but safe message.
Logging Matters
A production system should record useful context:
- timestamp
- request ID
- endpoint
- user/session context where appropriate
- error type
- stack trace
A request ID is particularly useful when tracing one request through multiple services.
Final Thoughts
Good error handling isn’t about hiding errors.
It’s about making errors understandable, observable, and safe.