How to fix Error: Callback threw an error (exception in callback handler) in Node.js
This error occurs when an exception is thrown inside a callback function and not properly caught. Since callbacks execute asynchronously, exceptions thrown within them cannot be caught by surrounding try-catch blocks, causing the error to propagate and potentially crash your application.
Quick fix
Fixes Error: Callback threw an error (exception in callback handler)
// ❌ Wrong - try-catch can't catch async errors
try {
fs.readFile('file.txt', (err, data) => {
throw new Error('Something went wrong');
});
} catch (error) {
// This will never catch the error
console.error(error);
}
// ✅ Correct - handle errors inside callback
fs.readFile('file.txt', (err, data) => {
try {
if (err) throw err;
// Process data
const result = JSON.parse(data); // Could throw
} catch (error) {
console.error('Error in callback:', error);
// Handle error appropriately
}
});- Add try-catch inside the callback function
- Use error-first callback convention
- Convert callbacks to Promises
- Add global uncaughtException handler
// ❌ Wrong - try-catch can't catch async errorstry {fs.readFile('file.txt', (err, data) => {throw new Error('Something went wrong');});} catch (error) {// This will never catch the errorconsole.error(error);}// ✅ Correct - handle errors inside callbackfs.readFile('file.txt', (err, data) => {try {if (err) throw err;// Process dataconst result = JSON.parse(data); // Could throw} catch (error) {console.error('Error in callback:', error);// Handle error appropriately}});Error: Callback threw an error (exception in callback handler)
What this error means
This error indicates that an exception was thrown inside a callback function and wasn't handled properly. In Node.js, callbacks execute asynchronously after the original function has returned, which means they run outside the scope of any try-catch block that was present when the callback was registered. When an exception is thrown in a callback and not caught, it propagates to the top of the call stack. Since there's no surrounding try-catch block in the callback's execution context, Node.js has no way to handle it gracefully. This results in an uncaught exception that can crash your entire application unless you have a global uncaughtException handler registered. The asynchronous nature of callbacks makes them fundamentally different from synchronous code. The callback is scheduled to run later (after I/O completes, a timer fires, etc.), so by the time it executes, the original function call has long since completed and any error handling context is gone.
Typical symptoms
- Application crashes with "Callback threw an error" message
- Stack trace shows error originated inside a callback function
- Error occurs after asynchronous operation completes
- Try-catch blocks around the async function call don't catch the error
- Process terminates unexpectedly during async operations
- Different behavior between synchronous and asynchronous code paths
Common causes
- Throwing an exception directly inside a callback function without error handling
- Missing try-catch block within the callback function body
- Attempting to catch callback errors with try-catch around the async function call
- Not following the error-first callback convention (err, result) pattern
- TypeError or ReferenceError occurring within callback due to undefined values
- Unchecked assumptions about data passed to the callback
- Mixing synchronous error handling patterns with asynchronous code
How to fix "Error: Callback threw an error (exception in callback handler)"
Move error handling into the callback itself, not around the async call:
// ❌ Wrong - try-catch can't catch async errors
try {
fs.readFile('file.txt', (err, data) => {
throw new Error('Something went wrong');
});
} catch (error) {
// This will never catch the error
console.error(error);
}
// ✅ Correct - handle errors inside callback
fs.readFile('file.txt', (err, data) => {
try {
if (err) throw err;
// Process data
const result = JSON.parse(data); // Could throw
} catch (error) {
console.error('Error in callback:', error);
// Handle error appropriately
}
});The try-catch must be inside the callback to catch exceptions that occur during callback execution.
Follow Node.js conventions by checking the error parameter first:
function processFile(callback) {
fs.readFile('config.json', 'utf8', (err, data) => {
// Always check err first
if (err) {
return callback(err); // Pass error to caller
}
try {
const config = JSON.parse(data);
callback(null, config); // null error, config result
} catch (parseError) {
callback(parseError); // Pass parsing error to caller
}
});
}
// Usage
processFile((err, config) => {
if (err) {
console.error('Failed to process file:', err);
return;
}
console.log('Config loaded:', config);
});Always return errors through the callback parameter rather than throwing.
Use util.promisify or convert to async/await for better error handling:
const { promisify } = require('util');
const fs = require('fs');
// Convert callback-based function to Promise
const readFileAsync = promisify(fs.readFile);
// Now you can use async/await with try-catch
async function loadConfig() {
try {
const data = await readFileAsync('config.json', 'utf8');
const config = JSON.parse(data);
return config;
} catch (error) {
console.error('Failed to load config:', error);
throw error; // Re-throw or handle as needed
}
}
// Or manually wrap in Promise
function readFilePromise(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', (err, data) => {
if (err) return reject(err);
resolve(data);
});
});
}Promises provide cleaner error handling that works with try-catch in async functions.
Register a safety net for uncaught exceptions (use as last resort, not primary error handling):
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error);
// Log error to monitoring service
// Clean up resources
// Exit gracefully (continuing after uncaught exception is unsafe)
process.exit(1);
});
// For Promise rejections
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
process.exit(1);
});Note: These handlers should be used for logging and cleanup, not for continuing execution. An uncaught exception leaves your application in an undefined state.
Check for null/undefined values before using them:
database.query('SELECT * FROM users', (err, results) => {
if (err) {
return handleError(err);
}
// Defensive checks to prevent throwing exceptions
if (!results || !Array.isArray(results)) {
return handleError(new Error('Invalid results'));
}
if (results.length === 0) {
return handleEmpty();
}
// Safe to process results now
results.forEach(user => {
if (user && user.id) {
processUser(user);
}
});
});Validate data before using it to avoid TypeErrors and ReferenceErrors.
Advanced notes
Why Async Exceptions Are Uncatchable
The JavaScript event loop processes callbacks separately from the original function call. When you call an async function like fs.readFile(), it returns immediately and the callback is queued for later execution. By the time the callback runs, the original call stack (including any try-catch blocks) has unwound completely.
Callback Hell and Modern Alternatives
Nested callbacks with error handling at each level create "callback hell" - deeply nested, hard-to-read code. Modern Node.js code uses Promises and async/await instead:
// Callback hell
fs.readFile('file1.txt', (err1, data1) => {
if (err1) return handleError(err1);
fs.readFile('file2.txt', (err2, data2) => {
if (err2) return handleError(err2);
fs.writeFile('combined.txt', data1 + data2, (err3) => {
if (err3) return handleError(err3);
console.log('Done');
});
});
});
// Clean async/await
async function combineFiles() {
try {
const data1 = await fs.promises.readFile('file1.txt');
const data2 = await fs.promises.readFile('file2.txt');
await fs.promises.writeFile('combined.txt', data1 + data2);
console.log('Done');
} catch (error) {
handleError(error);
}
}Error Recovery Safety
Once an uncaught exception occurs, Node.js considers your application to be in an undefined state. Variables may hold unexpected values, resources may not be properly released, and continuing execution can lead to data corruption or memory leaks. The recommended practice is to log the error, perform minimal cleanup, and restart the process using a process manager like PM2 or systemd.
Domain Module Deprecation
The domain module was Node.js's earlier attempt to handle async errors but has been deprecated due to its problematic design. Don't use it in new code - prefer Promises, async/await, and proper error handling patterns instead.
Frequently asked questions
- What does "Error: Callback threw an error (exception in callback handler)" mean?
- This error indicates that an exception was thrown inside a callback function and wasn't handled properly. js, callbacks execute asynchronously after the original function has returned, which means they run outside the scope of any try-catch block that was present when the callback was registered. When an exception is thrown in a callback and not caught, it propagates to the top of the call stack.
- How do I fix "Error: Callback threw an error (exception in callback handler)"?
- This error occurs when an exception is thrown inside a callback function and not properly caught. Since callbacks execute asynchronously, exceptions thrown within them cannot be caught by surrounding try-catch blocks, causing the error to propagate and potentially crash your application.
- What causes "Error: Callback threw an error (exception in callback handler)"?
- Throwing an exception directly inside a callback function without error handling Missing try-catch block within the callback function body Attempting to catch callback errors with try-catch around the async function call
- Is the "Error: Callback threw an error (exception in callback handler)" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.
Official resources & further reading
- 📚Node.js Official Documentation
- 📖Node.js Errors documentation(Official Docs)
- 📖Node.js uncaughtException event(Official Docs)
- 📝
- 📝