Uncaught TypeError: X is not a function

Quick answer

You called X(...) but X isn't a function at that point — it's undefined, an object, or something else non-callable. The three usual causes are a default/named import mismatch, a typo or wrong method for the value's real type, or a local variable shadowing the function you meant to call. Log typeof X right before the call to see what you actually have.

The exact error string

const result = data.calculate(5);
// Uncaught TypeError: data.calculate is not a function

import foo from "some-lib";
foo();
// Uncaught TypeError: foo is not a function

How to diagnose it in 30 seconds

Right before the failing call, log console.log(typeof X, X). The type tells you which cause applies: "undefined" — the import/export is mismatched or the property doesn't exist; "object" — you have the whole module or a data object instead of the function itself; a function, but the wrong one — a shadowing variable further down in scope.

Cause 1: default vs named export mismatch

// lib.js
export function formatDate(d) { /* ... */ }   // named export, no default

// ❌ app.js
import formatDate from "./lib.js";
formatDate();   // TypeError: formatDate is not a function (imported the whole module)

// ✅ app.js
import { formatDate } from "./lib.js";
formatDate();

Cause 2: wrong method for the value's real type

const data = await res.json();   // API returned { items: [...] }, not an array
data.map(x => x.id);
// ❌ data.map is not a function — data is an object, not an array

data.items.map(x => x.id);   // ✅ call the method on the actual array

Cause 3: a variable shadowing the function

import { map } from "lodash";

function process(map) {       // ❌ parameter named "map" shadows the import
  return map(items, fn);      // TypeError: map is not a function (it's the array you passed)
}

function process(list) {      // ✅ don't reuse the imported name
  return map(list, fn);
}

Cause 4: calling before it's assigned (hoisting)

doWork();
const doWork = function () { /* ... */ };
// ❌ ReferenceError first (TDZ) if truly before; but with `var` you'd get
//    "doWork is not a function" because var hoists the binding as undefined

var doWork = function () { console.log("done"); };
doWork();   // ✅ call after the assignment has run

Worked example: a broken build

This often shows up only after bundling, not in local dev:

// works in dev (unminified), fails in production:
import { helper } from "./utils";
helper();
// Uncaught TypeError: helper is not a function

// Check: does the built/minified bundle still export "helper"?
// Common causes: tree-shaking dropped an export it thought was unused,
// or a CommonJS/ESM interop mismatch changed the shape of the import.

Common variants at a glance

MessageLikely causeFix
X is not a function (import)default/named export mismatchmatch the import style to the export
X.map is not a functionX isn't actually an arraycheck the real shape, index into the array field
your own function, still failsa shadowing variable/paramrename the local binding
works in dev, fails in buildbundler dropped/renamed the exportinspect the built output
module.exports.X is not a functionCommonJS/ESM interop mismatchalign require/import style

Debugging checklist

Frequently Asked Questions

What does 'X is not a function' mean?

You wrote X(...) but the value bound to X at that point is not callable — it's undefined, an object, a string, or anything else that isn't a function. JavaScript only discovers this at the moment of the call, so the error always points at the exact line where you tried to invoke it.

Why does importing a library trigger this?

The most common cause is a default vs named export mismatch: import foo from 'lib' when the library only exports named bindings (import { foo } from 'lib'), or the reverse. You end up with the whole module object (or undefined) bound to foo, and calling foo() fails because foo isn't a function.

Why does a method that should exist say it's not a function?

Usually the value isn't the type you think it is — an array method called on an object, a string method called on a number, or the value came from JSON.parse and turned out to be null or a plain object instead of the class instance with that method. Log typeof value and the value itself right before the call.

Why does my own function say it's not a function?

A local variable or parameter with the same name is shadowing your function — declaring let map = [] in the same scope as a map() you meant to call, for example. Check for a same-named variable, parameter, or loop index declared between the function definition and the call site.

Why does it happen after minifying or bundling?

A build step can tree-shake an export it thinks is unused, target the wrong module format (CommonJS vs ESM interop), or bundle a stale cached chunk. Confirm the function still exists in the built output, and that your import/export syntax matches the bundler's expected module format.

How do I fix 'X is not a function' fast?

Log typeof X right before the call to see what it actually is. If it's undefined, check the import/export shape and spelling. If it's an object, you likely have the wrong value (module object instead of function, or a shadowing variable). Fix the source of the binding, not the call site.

More JavaScript & runtime errors

Browse the full reference for JavaScript, Node.js, and database errors — exact message, cause, and fix.

All Error References X.map is not a function HTTP Status Codes
About the author

Pasindu Ishan is a software developer based in Sri Lanka. He builds privacy-first developer tools at JSON Dev Tools.