This error occurs when you attempt to call a value as a function, but that value is not actually a function. It commonly happens due to typos in function names, calling properties that hold non-function values, or issues with module loading and scope.
The "TypeError: object is not a function" error is thrown by the JavaScript engine when code attempts to invoke something that is not callable. In JavaScript, only functions and objects with a [[Call]] internal method can be invoked with parentheses (). This error typically indicates one of several issues: you're calling a variable that holds a non-function value (like a number, string, object, or undefined), you've mistyped a function name, or you're experiencing module loading issues where the expected function hasn't been properly imported or defined yet. The error is particularly common in Node.js applications due to the complexity of module systems (CommonJS and ES modules), asynchronous operations, and circular dependencies that can result in undefined or partially loaded exports.
Use typeof to check if the value is actually a function before attempting to call it:
console.log(typeof myFunction); // Should output 'function'
if (typeof myFunction === 'function') {
myFunction();
} else {
console.error('myFunction is not a function, it is:', typeof myFunction);
}This will help you identify what type the value actually is.
Carefully review your code for misspelled function names. Common mistakes include:
// Wrong - typo in method name
const arr = [1, 2, 3];
arr.pus(4); // TypeError: arr.pus is not a function
// Correct
arr.push(4);
// Wrong - typo in DOM method
document.getElementByID('myId'); // TypeError
// Correct
document.getElementById('myId');Use your IDE's autocomplete feature to avoid typos.
Ensure that functions are correctly exported and imported:
// utils.js - Wrong: default export but importing as named
module.exports = { myFunction: function() {} };
// app.js - Wrong: default import
const myFunction = require('./utils'); // myFunction is an object
myFunction(); // TypeError: myFunction is not a function
// Fix 1: Use destructuring for named imports
const { myFunction } = require('./utils');
myFunction(); // Works!
// Fix 2: Or use default export correctly
// utils.js
module.exports = function myFunction() {};
// app.js
const myFunction = require('./utils');
myFunction(); // Works!For ES modules:
// utils.mjs
export function myFunction() {}
// app.mjs - Wrong
import myFunction from './utils.mjs'; // undefined
myFunction(); // TypeError
// Correct - use named import
import { myFunction } from './utils.mjs';
myFunction(); // Works!Circular dependencies can cause modules to be partially loaded:
// moduleA.js
const { funcB } = require('./moduleB');
exports.funcA = function() {
funcB(); // May fail if moduleB isn't fully loaded
};
// moduleB.js
const { funcA } = require('./moduleA');
exports.funcB = function() {
funcA(); // May fail if moduleA isn't fully loaded
};Fix by restructuring your code to eliminate circular dependencies:
// Create a third module for shared functionality
// shared.js
exports.sharedLogic = function() { /* ... */ };
// moduleA.js
const { sharedLogic } = require('./shared');
exports.funcA = function() {
sharedLogic();
};
// moduleB.js
const { sharedLogic } = require('./shared');
exports.funcB = function() {
sharedLogic();
};Use tools like madge to detect circular dependencies:
npx madge --circular src/Ensure functions are available before calling them in async contexts:
// Wrong - function may not be assigned yet
let myFunction;
setTimeout(() => {
myFunction(); // TypeError if called before assignment
}, 100);
// Later in code
myFunction = function() { console.log('Hello'); };
// Fix 1: Define function before use
const myFunction = function() { console.log('Hello'); };
setTimeout(() => {
myFunction(); // Works
}, 100);
// Fix 2: Use async/await with proper sequencing
async function loadAndExecute() {
const module = await import('./myModule.js');
const myFunction = module.default;
if (typeof myFunction === 'function') {
myFunction();
}
}If you're passing functions as callbacks, validate them:
// Wrong - passing non-function as callback
function processData(callback) {
callback(); // TypeError if callback is not a function
}
processData('not a function'); // TypeError
// Fix: Add validation
function processData(callback) {
if (typeof callback !== 'function') {
throw new TypeError('Callback must be a function');
}
callback();
}
// Or provide a default
function processData(callback = () => {}) {
if (typeof callback !== 'function') {
console.warn('Invalid callback provided, using default');
callback = () => {};
}
callback();
}Ensure classes are instantiated with new keyword:
// Wrong - calling class without new
class MyClass {
constructor() {
this.value = 42;
}
}
const instance = MyClass(); // TypeError: Class constructor cannot be invoked without 'new'
// Correct
const instance = new MyClass();For constructor functions:
function MyConstructor() {
this.value = 42;
}
// Wrong
const obj = MyConstructor(); // TypeError in strict mode
console.log(obj.value); // TypeError: Cannot read property 'value' of undefined
// Correct
const obj = new MyConstructor();
console.log(obj.value); // 42Scope and Hoisting Issues
Function declarations are hoisted to the top of their scope, but function expressions and arrow functions are not:
// Works - function declaration is hoisted
myFunction();
function myFunction() { console.log('Hello'); }
// TypeError - function expression not hoisted
myFunction();
const myFunction = function() { console.log('Hello'); };Variable Shadowing
Local variables can shadow function references:
const map = [1, 2, 3].map; // Store reference to Array.prototype.map
function processArray() {
const map = 'not a function'; // Shadows the outer map variable
return [1, 2, 3].map(x => x * 2); // Works - uses Array.prototype.map
// But this would fail:
// return map(x => x * 2); // TypeError
}Property Access Timing
When destructuring or accessing nested properties, ensure the parent exists:
const config = { api: { get: function() {} } };
// Wrong - if config.api doesn't exist yet
const { get } = config.api; // TypeError if config.api is undefined
// Safe approach
const get = config?.api?.get;
if (typeof get === 'function') {
get();
}Native API Changes
Some native APIs have been deprecated or changed across Node.js versions. Always check the Node.js documentation for the version you're using to ensure the API exists and is used correctly.
TypeScript Benefits
Using TypeScript can catch many of these errors at compile time:
function processCallback(callback: () => void) {
callback(); // TypeScript ensures callback is a function
}
processCallback('not a function'); // Compile errorError: EMFILE: too many open files, watch
EMFILE: fs.watch() limit exceeded
Error: Middleware next() called multiple times (next() invoked twice)
Express middleware next() called multiple times
Error: Worker failed to initialize (worker startup error)
Worker failed to initialize in Node.js
Error: EMFILE: too many open files, open 'file.txt'
EMFILE: too many open files
Error: cluster.fork() failed (cannot create child process)
cluster.fork() failed - Cannot create child process