How does error handling work across callback, promise and EventEmitter APIs in Node.js?
Take a moment.
Say your answer out loud or write it down first — retrieval is what makes it stick. Reveal when you're ready.
Short answer
Callbacks follow error-first convention (err, result). Promises/async use try/catch and .catch. EventEmitters emit 'error' events that must have a listener — unhandled ones crash the process. Unhandled rejections also crash by default in modern Node.
Detailed explanation
Three conventions coexist because Node's APIs evolved over a decade. Error-first callbacks reserve the first argument for errors — null on success; forgetting to return after handling creates double-invocation bugs. Promises centralize failures into .catch chains or try/catch around await; async functions that forget await silently swallow errors. EventEmitters are different: 'error' is special, and emitting one with no listener throws — crashing the process by design (fail-fast for unrecoverable state like broken sockets). Modern defaults enforce discipline: unhandled promise rejections terminate the process (since v15) rather than warn. Server strategy: catch at boundaries (route handlers, middleware), wrap async entry points, use process.on('uncaughtException') only to log-and-exit gracefully — never to continue running in unknown state. Domain-specific wrappers (Express async error forwarding, Fastify hooks) standardize per-framework.
Example
// Callback style:
fs.readFile(path, (err, data) => {
if (err) return next(err); // return prevents double-calls
process(data);
});
// Promise/async style:
try {
const data = await fs.promises.readFile(path);
process(data);
} catch (err) {
next(err);
}
// EventEmitter style:
socket.on('error', (err) => logger.error(err)); // required listenerInterview tip
Organize strictly by the three API styles, then land the modern behavior — unhandled rejections crash since v15 — which shows you know current runtime semantics.
Common mistakes
- Forgetting return after error-first callback handling.
- Not knowing missing 'error' listeners crash the process.