Callback Error Handling in JavaScript
Error handling with callbacks is error-first. Here is the convention and how to do it right.
Callback Error Handling in JavaScript
Error handling with callbacks uses the error-first convention (Node.js style). Understanding it is essential for Node.js and callback-based APIs.
The Error-First Convention
The callback's first argument is an error. If there is no error, it is null. The second argument (and beyond) is the result.
fs.readFile("file.txt", (err, data) => { if (err) { console.error("Error:", err); return; } console.log("Data:", data); }); `` ### Always Check for the Error First ```js // good: check err first fetchUser(id, (err, user) => { if (err) { handleError(err); return; } render(user); }); // bad: ignoring err (user might be undefined) fetchUser(id, (err, user) => { render(user); // if err, user is undefined -> TypeError }); `` ### The Error-First Pattern ```js function myAsyncOperation(arg, callback) { setTimeout(() => { if (!arg) { callback(new Error("arg is required")); return; } callback(null, arg.toUpperCase()); }, 100); } `` When creating your own callback-based APIs, follow the convention: `callback(err, result)`. ### Propagating Errors ```js fetchUser(id, (err, user) => { if (err) { callback(err); return; } // propagate fetchPosts(user, (err, posts) => { if (err) { callback(err); return; } // propagate callback(null, { user, posts }); }); }); `` Each step checks and propagates the error. This is repetitive (one reason callback hell is bad). ### Promises Are Better for Errors ```js async function main() { try { const user = await fetchUserP(id); const posts = await fetchPostsP(user); return { user, posts }; } catch (err) { handleError(err); } } `` One `try/catch` handles all errors. Much cleaner than error-first callbacks. ### The Takeaway Callback error handling uses the error-first convention: `callback(err, result)`. Always check `if (err)` first and return early. Propagate errors to the caller. This is repetitive, which is why promises (with `.catch`) and async/await (with `try/catch`) are better for error handling.
The Node.js convention where the callback's first argument is an error (null if no error). The second argument and beyond are the result. Example: fs.readFile(path, (err, data) => { if (err) ... }).
Check if (err) first and return early. If there is an error, handle it and return. If not, use the result. Always check for the error before using the result to avoid TypeError (result might be undefined).
Because each callback must check if (err) and propagate the error to the caller. In a chain of callbacks, this check is repeated at every level. Promises solve this with a single .catch, and async/await with a single try/catch.
Check if (err) in each callback. If there is an error, call the outer callback with the error and return: if (err) { callback(err); return; }. This passes the error up the chain.
Promises use .catch for errors, which catches errors from anywhere in the .then chain. async/await uses try/catch. One handler covers all errors, instead of checking if (err) at every callback level.
Ready to master React completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master React
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

