Error-First Callbacks

Node's classic async pattern passes an error as the first argument.

Syntaxfn((err, data) => { if (err) ...; use(data); })

Before promises, Node used callbacks for asynchronous work. Node follows the error-first convention: the callback's first argument is an error (or null if all went well), and the result follows.

Always check the error

The first thing a callback should do is check whether err is set, and handle it before using the data.

Example

Example · javascript
const fs = require('fs');

fs.readFile('data.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Failed:', err.message);
    return;
  }
  console.log('Got data:', data);
});

When to use it

  • An older Express middleware uses the error-first callback pattern `(err, req, res, next)` to pass database errors up the middleware chain.
  • A file-upload library accepts a `callback(err, filePath)` so callers can handle both success and failure in one function.
  • A Node.js core `fs.readFile` call uses a callback to avoid blocking the event loop while disk I/O completes in the background.

More examples

Error-first callback pattern

Shows the Node.js error-first callback convention -- always check `err` before using the result.

Example · js
const fs = require('fs');

fs.readFile('data.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Read failed:', err.message);
    return; // early exit on error
  }
  console.log('Content:', data);
});

Write your own callback function

Implements a custom error-first callback where `null` in the first argument signals success.

Example · js
function divide(a, b, callback) {
  if (b === 0) return callback(new Error('Cannot divide by zero'));
  callback(null, a / b);
}

divide(10, 2, (err, result) => {
  if (err) console.error(err.message);
  else console.log('Result:', result); // 5
});

Callback hell and why to avoid it

Illustrates callback hell -- deeply nested callbacks -- and why promises/async-await are preferred.

Example · js
// Anti-pattern: deeply nested callbacks
fs.readFile('a.txt', 'utf8', (err, a) => {
  fs.readFile('b.txt', 'utf8', (err, b) => {
    fs.writeFile('c.txt', a + b, (err) => {
      console.log('Done'); // hard to read and handle errors
    });
  });
});
// Prefer: fs/promises with async/await (see next lesson)

Discussion

  • Be the first to comment on this lesson.