Skip to content
UniCircle
MediumConceptualError handling

Error-first callbacks and unhandled rejections

Question NODE-ERR-001

What is the error-first callback convention in Node.js? How do errors work with promises, and what happens to an unhandled promise rejection or an uncaught exception?

Show the explanation

Model answer. Older Node APIs take a callback whose first argument is the error (or null), and the result after it:

JavaScript
fs.readFile('config.json', 'utf8', (err, text) => {
  if (err) return console.error('could not read config', err);   // always check first
  start(JSON.parse(text));
});

The convention makes it impossible to forget that an operation can fail. But errors thrown inside the callback are not caught by a try around readFile, and nesting many callbacks gets unreadable ("callback hell").

With promises / async–await, errors become rejections, which you handle with .catch() or try/catch around await. util.promisify converts callback APIs, and most core modules have promise versions (fs/promises).

Process-level failures:

  • Unhandled rejection: since Node 15 it crashes the process by default.
  • Uncaught exception: also crashes. A process.on('uncaughtException') handler should only log and exit, because the app may be in a broken state.

In production, let the process crash, and have a supervisor (systemd, Docker, PM2, Kubernetes) restart it, with logs and alerts.

Original UniCircle question. Last reviewed 22 Oct 2026.