A not-a-function TypeError means the expression being called produced a value without JavaScript callability. Inspect the exact callee, then trace shadowing, overwrites, import shape, async results, plugin data, or object type back to its producer.
Optional call syntax handles only nullish absence, not a malformed present value. Strong boundaries validate callbacks and plugins once, keep module contracts explicit, and regression-test the invalid runtime value.
The error TypeError: X is not a function occurs when you try to call something as a function that isn't actually a function. This happens when the variable is undefined, null, or a different data type.
// [wrong] Problem
let myFunc = 'not a function';
myFunc(); // TypeError: myFunc is not a function
// [ok] Solution 1: Check if it's a function
if (typeof myFunc === 'function') {
myFunc();
}
// [ok] Solution 2: Define the function properly
function myFunc() {
console.log('I am a function');
}
myFunc(); // Works!
// Variable is a string
let calculate = 'sum';
calculate(5, 10); // TypeError: calculate is not a function
// Variable is a number
let process = 42;
process(); // TypeError: process is not a function
// Variable is undefined
let handler;
handler(); // TypeError: handler is not a function
// Check type before calling
let calculate = 'sum';
if (typeof calculate === 'function') {
calculate(5, 10);
} else {
console.error('calculate is not a function');
}
// Define as a function
let calculate = function(a, b) {
return a + b;
};
calculate(5, 10); // 15
// Or use arrow function
let calculate = (a, b) => a + b;
calculate(5, 10); // 15
function calculateSum(a, b) {
return a + b;
}
// Typo: calculateSun instead of calculateSum
calculateSun(5, 10); // TypeError: calculateSun is not a function
// Case sensitivity
CalculateSum(5, 10); // TypeError: CalculateSum is not a function
// Fix the typo
function calculateSum(a, b) {
return a + b;
}
calculateSum(5, 10); // 15 - Works!
// Use IDE autocomplete to avoid typos
// Use ESLint to catch undefined functions
const user = {
name: 'John',
age: 30
};
user.greet(); // TypeError: user.greet is not a function
// Or accessing wrong property
const calculator = {
sum: function(a, b) { return a + b; }
};
calculator.add(5, 10); // TypeError: calculator.add is not a function
// Add the method to the object
const user = {
name: 'John',
age: 30,
greet: function() {
return `Hello, I'm ${this.name}`;
}
};
user.greet(); // "Hello, I'm John"
// Or use correct property name
const calculator = {
sum: function(a, b) { return a + b; }
};
calculator.sum(5, 10); // 15
// Check if method exists
if (typeof user.greet === 'function') {
user.greet();
}
let users = null;
users.map(u => u.name); // TypeError: users.map is not a function
// Or undefined
let items;
items.filter(i => i.active); // TypeError: items.filter is not a function
// Or wrong type
let data = 'not an array';
data.forEach(item => console.log(item)); // TypeError!
// Initialize as array
let users = [];
users.map(u => u.name); // Works (returns [])
// Check if array before using
let users = null;
if (Array.isArray(users)) {
users.map(u => u.name);
}
// Use optional chaining with default
let users = null;
const names = users?.map(u => u.name) || [];
// Or nullish coalescing
let users = null;
(users ?? []).map(u => u.name);
function calculate(a, b) {
return a + b;
}
// Accidentally overwrite
calculate = 42;
calculate(5, 10); // TypeError: calculate is not a function
// Or in loop
for (let calculate = 0; calculate < 10; calculate++) {
// calculate is now a number
}
calculate(5, 10); // TypeError!
// Use const to prevent reassignment
const calculate = function(a, b) {
return a + b;
};
// calculate = 42; // TypeError: Assignment to constant variable
// Use different variable names
function calculate(a, b) {
return a + b;
}
for (let i = 0; i < 10; i++) {
// Use 'i' instead of 'calculate'
}
calculate(5, 10); // Works!
A not-a-function TypeError means the expression before parentheses produced a value that is not callable. In `service.load()`, inspect `service.load`; in `factory()()`, determine whether the first call returned a function. The reported identifier may be transformed or incomplete, so pause on the exception and evaluate the exact callee expression.
`typeof value === "function"` is a narrow runtime callability check, but it does not prove argument, return, receiver, permission, or side-effect contracts. Use it only when multiple input types are intentionally supported. A required callback should be validated at the boundary and rejected with context instead of silently skipped.
Optional call syntax, `callback?.()`, skips the call only when callback is null or undefined. If callback contains a string or object, it still throws. That distinction is useful: absence can be optional, while a present value of the wrong type is malformed input.
The stack frame containing the call identifies where the invalid assumption surfaced. Trace backward to the assignment, import, property overwrite, or return statement that supplied the callee. Wrapping the call in try/catch does not restore the missing behavior.
A local parameter, import, or variable can shadow a function with the same name. Search the lexical scope and use the debugger scope panel rather than assuming a globally visible declaration is being called. Clear names such as `formatText` and `formattedText` reduce collisions between operations and results.
An object method can be overwritten by data assignment, object spread order, deserialization, or a plugin merge. Freeze stable configuration where appropriate, validate extension objects before merging, and avoid combining untrusted data with behavior-bearing objects. JSON cannot carry functions, but parsed keys can replace methods when assigned carelessly.
Class instance fields can shadow prototype methods when they use the same name. A field initialized with data wins during lookup, so `instance.save()` can fail even though `Class.prototype.save` exists. Define field and method namespaces deliberately and let type checking reject incompatible overrides.
DOM APIs sometimes expose properties that look like methods in examples for a different object type. Confirm the runtime constructor and API contract. A NodeList, HTMLCollection, array, iterator, and plain object support different operations even when developer tools display similar collections.
Module namespace shape depends on how a package exports values and how tooling handles CommonJS interoperability. A default export, named export, and namespace object are not interchangeable. Inspect the package entry and runtime module value; do not cycle through import syntaxes until one happens to run.
Dynamic `import()` returns a Promise for a module namespace object. Calling that Promise or calling the namespace itself produces a TypeError. Await the import, select the documented export, and validate optional plugin exports before registration. Keep server and browser module targets consistent.
An async function always returns a Promise. Code expecting a returned callback must await the Promise first, while code expecting data must not call the resolved value. Name factory APIs to communicate whether they return a function, an object, a Promise, or a subscription.
Mocks frequently create this error when a test replaces a module function with plain data or forgets a default export wrapper. Type the mock against the real interface, reset it between tests, and include one integration test that loads the actual module format.
A method may exist but still fail after extraction because its receiver is missing; that usually throws inside the method rather than at the call itself. Preserve method invocation, bind at the callback boundary, or redesign the function to accept state explicitly. Distinguish a non-callable property from a callable method with an invalid receiver.
Getters can return different types over time, and proxy `get` traps can synthesize properties dynamically. Calling such a property executes the getter or trap before callability is checked. Keep behavior properties stable, avoid side effects in lookup, and validate proxy extension contracts at registration.
A callable Proxy must wrap a callable target; an apply trap cannot make a plain object callable. Similarly, objects with a `call` property are not themselves functions. JavaScript callability is an internal capability, not a naming convention that application code can add.
Some APIs use constructors rather than ordinary calls, or ordinary factories rather than constructors. Calling a class without `new` has its own TypeError, while using `new` on an arrow or concise method fails because it is not constructable. Read the API invocation contract rather than guessing from capitalization alone.
Test required callbacks with a function, missing value, wrong present type, throwing implementation, and asynchronous implementation where accepted. Assert whether the boundary rejects, skips, awaits, or propagates. An optional callback test should prove that malformed present values still fail.
For plugin systems, validate the entire plugin interface once during registration and store a normalized internal representation. Include plugin name, version, missing method, and host release in the error without logging configuration secrets. Do not rediscover interface defects on the first user action.
Pause on exceptions and inspect `typeof`, prototype, own property descriptor, import namespace keys, and the assignment history of the callee. A data breakpoint or proxy used only in a controlled reproduction can reveal who overwrites a method. Remove invasive instrumentation after diagnosis.
Static types, lint rules against shadowing, immutable interfaces, and schema validation reduce risk, but runtime checks remain necessary for plugins, network data, and mixed module systems. Convert the exact invalid value into a regression fixture and verify the intended call actually occurs after repair.
This error occurs when you try to call something as a function that isn't actually a function. Common causes include typos in function names, calling undefined variables, using wrong data types, or accidentally overwriting functions.
Check if the variable is actually a function using typeof, fix any typos in function names, ensure the function is defined before calling it, and verify you're calling the correct property name.
This happens when calling .map() on a variable that is not an array. The variable might be null, undefined, or a different data type. Check with Array.isArray() or use optional chaining.
Explore 500+ free tutorials across 20+ languages and frameworks.