Error-First Callbacks: Node.js's Original Async Handler
The error-first callback is a Node.js convention: check for rain before unpacking the picnic. The first argument to any async callback is for an error. It's the standard for older core modules like fs.
Why it exists
Synchronous try...catch blocks don't work for asynchronous code. The try block finishes executing long before an async task—like a file read or database query—completes or fails. Node.js needed a consistent way to pass an error from a future point in the event loop back to the originating code's context.
The mental model
Think of it as "check for rain before unpacking the picnic." Your callback function receives its arguments, and the very first thing you do is check if the first argument—the error—is present. If it is, you handle the storm and stop. If it's null, you're clear to proceed with the rest of the arguments, which contain the successful result.
How it works
An asynchronous function takes a callback as one of its last arguments. This callback is designed to accept at least one parameter. By convention, the first parameter is always an Error object (or null if no error occurred). Any subsequent parameters are the successful results of the operation. Your callback logic must always start with if (err) { ... handle error ... } and typically stop execution with a return.
When to use it
You will encounter this pattern constantly when working with older but still common Node.js core modules (like fs, crypto), many community packages on npm, and in the function signature for Express error-handling middleware. Understanding it is essential for working with much of the Node.js ecosystem.
When not to use it
For new projects, modern JavaScript with async/await and try...catch is almost always a cleaner and more readable choice. Promises and async/await were designed to solve the verbosity and "callback hell" that can arise from deeply nested error-first callbacks. Use the modern syntax unless you are interfacing with an older API that requires a callback.
One canonical example
Reading a file using the built-in fs module is the classic example. fs.readFile('path/to/file.txt', 'utf8', (err, data) => { if (err) { console.error('Failed to read file:', err); return; } console.log('File contents:', data); }); If the file doesn't exist, the err object will be populated and data will be undefined. If it succeeds, err will be null.
Interview question
In an error-first callback, what is the specific purpose of the very first argument?
- a.To define the context (this) for the callback's execution.
- b.To manage the flow control for subsequent asynchronous operations.
- c.To provide the successful data returned by the asynchronous task.
- d.To signal the presence of an error or the successful completion of the task.Correct
Why? this is the answer
The card states that the first parameter is "always an Error object (or null if no error occurred)," which means it signals whether an error occurred or if the task completed successfully. Option C is incorrect because successful data is passed in subsequent arguments, not the first.
Just read this? Test yourself on what you have been reading.
Read the original → nodejs.org
- #node.js
- #asynchronous
- #callbacks
- #error handling
Put your scrolling time to good use
Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on node.js — each one lists the topics its interview covers.
See open roles