Skip to content
Happy Programming Guide
Start learning
JavaScript

Fixing “TypeError: x is not a function” in JavaScript

You called something that is not callable. The five ways that happens, from forEach on a NodeList to .then on a plain value, and how the message tells you which one it is.

A person working on a laptop

TypeError: x is not a function means the code put brackets after something that is not a function — a number, a string, an object, or, most often, undefined. The name before “is not a function” tells you exactly what you tried to call. From there it is one of five situations, and each has a distinct fix.

Reading the message#

JavaScript
const total = 42;
total();                    // TypeError: total is not a function

const user = { name: 'Ann' };
user.greet();               // TypeError: user.greet is not a function

items.forEach(fn);          // TypeError: items.forEach is not a function

The part before “is not a function” is the expression you called. If it is user.greet, then user exists but has no greet. If it is items.forEach, then items exists but is not the kind of thing with a forEach. Log the object and check its type:

JavaScript
console.log(typeof items, items);
console.log(Array.isArray(items));

Cause 1: the method does not exist on that type#

The most common shape. The value is real but of a different type than the code assumes:

Error Likely value Fix
items.map is not a function an object, or a string Use Object.values(items).map, or check the API returns an array
list.forEach is not a function a NodeList from querySelectorAll in an old browser, or an HTMLCollection Array.from(list).forEach
str.push is not a function a string, not an array Split first, or use concatenation
date.getFullYear is not a function a string that looks like a date new Date(str) first
json.map is not a function the raw response, not the parsed body await response.json() first

The API-returns-an-object case is worth a special look. Many APIs wrap their list: { results: [...] }. The code maps over the wrapper instead of results.

Cause 2: .then is not a function#

JavaScript
function getUser() {
  return { name: 'Ann' };          // returns a plain object
}
getUser().then(u => ...);          // TypeError: getUser(...).then is not a function

Only promises have .then. The function is synchronous, or it forgot to return the promise:

JavaScript
function getUser() {
  fetch('/api/user');               // the promise is created and thrown away
}
getUser().then(...)                 // undefined.then - not a function

function getUser() {
  return fetch('/api/user');        // return it
}

A missing return inside a .then chain produces the same error one step later. async functions always return a promise, which makes this class of bug disappear.

Cause 3: import and export mismatches#

JavaScript
// util.js
export function format(n) { ... }

// app.js
import format from './util.js';    // default import - but there is no default export
format(3);                          // TypeError: format is not a function

A default import of a module with only named exports gives undefined. Match the style: import { format } from './util.js'. The reverse mistake, import { x } from a module that only has a default export, does the same. In CommonJS, const format = require('./util') when the module exports an object gives you the object, and format() fails; you wanted require('./util').format.

Circular imports produce a subtler version: the module is imported before it has finished loading, so the function is temporarily undefined. Restructure so the cycle is broken.

Cause 4: a shadowed or reassigned name#

JavaScript
function process(items) {
  const filter = items.length > 10;     // reuses the name of a function elsewhere
  return filter(items);                  // TypeError: filter is not a function
}

A local variable with the same name as a function, or a function accidentally reassigned (fn = fn() instead of result = fn()), replaces it with a value. Look for the name being declared or assigned nearby.

Cause 5: calling too early or on the wrong object#

JavaScript
const el = document.querySelector('.btn');
el.addEventListener('click', ...);      // fine
document.querySelector('.btn').on('click', ...);   // .on is jQuery, not DOM

Methods from a library used on plain objects, jQuery methods on DOM elements, or a plugin method called before the plugin script loaded. Confirm the object really is the type the method belongs to, and that the script defining the method comes first.

The optional-call operator#

JavaScript
onSuccess?.(result);      // calls onSuccess only if it is defined

Use this for genuinely optional callbacks — a configuration object where the handler may be omitted. As with optional chaining, do not use it to hide a function that should exist.

Questions people ask#

Why does it say “is not a function” rather than “does not exist”?

Because reading a missing property gives undefined without complaint; only calling it fails. The property read succeeded, the call did not.

What about “is not a constructor”?

The same idea with new: you used new on something that is not a class or constructor function, often because of the same import mismatch.

Does TypeScript prevent this?

Mostly. It catches calling a non-function and calling a method that does not exist on the declared type. It cannot catch an API returning a different shape than its type says, which is why validating at the edge still matters.

The function is definitely defined; why does it fail intermittently?

Timing. The script that defines it loads after the script that calls it, or a circular import leaves it undefined on some load orders. Check the script order and the module graph.

Where to go next#

Fixing 'x is not a constructor'Read next

Keep reading

Keep going — pick your next guide

The fastest way to improve is to read one guide, then build the thing it describes. Start with the basics, or jump straight to a project.

Ask a question or share what worked

Your email address will not be published. Required fields are marked *