This error means the code tried to call something as a function, with ( ) after it, and the value in that spot was not a function at all. It was undefined, a string, a plain object, or a method that does not exist on that type. The message names the expression that failed, and the fix is always to work out what that value actually is at runtime and why it is not the function the code expected.
TypeError: user.greet is not a function says the object exists, but it has no callable greet. TypeError: undefined is not a function (common in minified builds) means the thing being called was never assigned at all.console.log(typeof thing, thing). The output tells you instantly whether it is undefined, an object, or a string wearing a function's name..map() or .forEach() on a plain object or a string, often because an API returned an object where an array was expected.console.log(Object.keys(obj)) settles most cases in seconds, the method is missing, renamed, or one level deeper than expected.import fn from './x' for a default export, import { fn } from './x' for a named one, and call the export, not the namespace.onDone?.() is right for an optional hook and wrong as a blanket over every call, it hides the bug the same way optional chaining does elsewhere.What does “(intermediate value) is not a function” mean? Minified or transpiled code rewrote the call, so the original name is lost. It is the same error: something that is not a function was called. Debug it in the unminified build or with source maps enabled.
Why does it fail in production but not in development? Usually minification removed the names, making it harder to read, combined with real data arriving in a shape the test data never had. Reproduce with production-shaped data and check the type of the value at the failing call.
Is “not a function” the same as “is not defined”? No. Not defined (a ReferenceError) means the name itself does not exist. Not a function means the name exists but holds a value that cannot be called.