How to Resolve "TypeError: callback is not a function" Error in JavaScript
The TypeError: callback is not a function is a common error in JavaScript that occurs when you attempt to invoke a variable as a function, but its value is not actually a function at the time of execution. This most frequently happens when a function expects a callback argument, but is called without one.
This guide will explain the fundamental reason this error occurs and teach you the modern, standard methods for preventing it by providing a default parameter or by conditionally checking for the function's existence.
The Core Problem: Trying to Invoke a Non-Function Value
In JavaScript, functions can be passed as arguments to other functions. The parameter that receives the function is commonly named callback. The error occurs when the code tries to execute this parameter using parentheses (), but the parameter's value is not a function.
Problem: when a function parameter is not provided in a function call, its value inside the function is undefined.
function executeCallback(callback) {
// If `executeCallback` is called with no arguments, `callback` is `undefined`.
console.log(typeof callback); // Output: 'undefined'
// This line is equivalent to calling `undefined()`, which throws the error.
callback();
}
// Problem: We are calling the function without providing a callback.
executeCallback();
Error Output:
Uncaught TypeError: callback is not a function
The Most Common Cause: Forgetting to Pass a Callback
The error is a direct result of calling a function that expects a callback without providing one.
function myFunc(data, callback) {
// ... some logic
callback(data); // This will fail if `callback` is undefined.
}
// Incorrect: The second argument (the callback) is missing.
myFunc({ id: 1 });
Solution 1 (Recommended Best Practice): Default Parameters
The cleanest and most modern way to prevent this error is to provide a default value for your callback parameter using ES6 default parameters. You can set the default to an empty function.
Solution:
// Set a default value for the `callback` parameter.
function myFunc(data, callback = () => {}) {
// If no callback is provided, it defaults to an empty, harmless function.
const processedData = { ...data, status: 'processed' };
// This line is now safe to call, even if the user didn't pass a function.
callback(processedData);
}
// This call is now safe and will not throw an error.
myFunc({ id: 1 });
// This call will work as expected.
myFunc({ id: 2 }, (result) => {
console.log('Callback received:', result);
});
This is the recommended best practice for its readability and robustness.
Solution 2 (Alternative): Conditionally Check for the Callback
An alternative, more traditional approach is to explicitly check if the callback is a function before attempting to call it. This is done using the typeof operator.
Solution:
function myFunc(data, callback) {
const processedData = { ...data, status: 'processed' };
// Only execute the callback if it is actually a function.
if (typeof callback === 'function') {
callback(processedData);
}
}
// Both of these calls are now safe.
myFunc({ id: 1 });
myFunc({ id: 2 }, (result) => console.log(result));
This method is perfectly valid and is very common in older codebases or in situations where default parameters are not used.
Practical Example: An Asynchronous Function with Optional Callbacks
This is a very common real-world scenario. A function fetches data and accepts two optional callbacks: onSuccess and onError.
function fetchData(userId, options = {}) {
// Use object destructuring to get callbacks with default values.
const { onSuccess = () => {}, onError = () => {} } = options;
console.log(`Fetching data for user ${userId}...`);
setTimeout(() => {
// Simulate a network request
if (userId === 1) {
const data = { id: 1, name: 'Alice' };
onSuccess(data); // Safely call the success callback
} else {
const error = new Error('User not found');
onError(error); // Safely call the error callback
}
}, 1000);
}
// Call with both callbacks
fetchData(1, {
onSuccess: (data) => console.log('Success:', data),
onError: (err) => console.error('Error:', err.message),
});
// Call with no callbacks (no error will be thrown)
fetchData(2);
// Call with callbacks (errow will be thrown)
fetchData(2, {
onSuccess: (data) => console.log('Success:', data),
onError: (err) => console.error('Error:', err.message),
});
Conclusion
The TypeError: callback is not a function is a clear signal that you are attempting to invoke a variable (often a function parameter) that does not hold a function.
To solve this, make your functions more robust by:
- Providing a default empty function for your callback parameter:
callback = () => {}. This is the recommended modern approach. - Conditionally checking the type before execution:
if (typeof callback === 'function') { ... }.
By implementing one of these patterns, you can create flexible functions that safely handle optional callbacks without throwing errors.