Error Handling
- Error Handling
- Node.js
- Express
Deciding deliberately what a service does when something goes wrong, separating expected errors from unexpected ones and returning safe, useful responses.
What you'll understand
- Why deliberate error handling matters
- The difference between expected and unexpected errors
- How to return errors that clients and logs can both use
Explanation
Error handling is deciding what your program does when something goes wrong. Things will go wrong: invalid input, a missing record, a database that is down. The difference between a robust service and a fragile one is how deliberately it responds. Unhandled errors crash requests, leak internal details, and leave clients guessing.
It helps to separate expected from unexpected errors. Expected errors are normal outcomes: a resource is not found (404), input is invalid (400), the user is not allowed (403). You handle these where they happen and return a clear status. Unexpected errors are bugs or outages you did not plan for; these should be caught by a central handler that logs the details and returns a generic 500 without exposing internals.
A good error response serves two audiences. The client needs a stable status code and a safe message it can act on. Your logs need the full detail, the stack trace and context, so you can diagnose the problem. Never send internal details to the client, and never swallow an error silently.
Examples
This TypeScript example uses a central Express error handler to turn thrown errors into safe responses while logging the detail:
app.use((err, req, res, next) => {
logger.error(err); // full detail for your logs
if (err instanceof NotFoundError) {
return res.status(404).json({ message: 'Not found' });
}
// unexpected error: do not leak internals
res.status(500).json({ message: 'Something went wrong' });
});Common mistakes
- Swallowing errors with an empty catch block so failures pass silently.
- Sending stack traces or database messages to the client.
- Returning 200 with an error buried in the body instead of an error status.
- Handling the same expected error differently in every route.
Best practices
- Distinguish expected errors, which return a specific status, from unexpected ones, which you log and return as 500.
- Centralize unexpected-error handling so every route behaves consistently.
- Log full detail for yourself; return safe, generic messages to clients.
- Never expose internal details in a response.
Further reading
- MDN, HTTP response status codes — https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
- Node.js, Error handling guide — https://nodejs.org/en/learn/asynchronous-work/handling-errors