X is not a function
The code called something that isn’t a function, most often .map on API data that came back as an object or a string instead of an array.
Also appears as
- TypeError: data.map is not a function. (In 'data.map((todo) => todo.title)', 'data.map' is undefined)
Prompt to fix it
My app throws "TypeError: data.map is not a function" (or another "... is not a function" error). Log the value right before the call and tell me what it really is. If it’s an API or Supabase response, extract the actual array (for example data from { data, error }, or body.items) and update the TypeScript types to match. Check res.ok and errors before saving responses into state. If it’s a missing callback prop or a mismatched import, fix where it’s passed or exported. Don’t wrap the call in try/catch or a typeof check just to silence it.
Paste into Layerwise or any AI coding tool.
What it means
The parentheses in data.map(...) mean “call this.” JavaScript found data, but data.map wasn’t a function, so the call failed. With .map, .filter, or .forEach, that almost always means data isn’t an array, because those methods exist only on arrays.
APIs rarely hand back a bare list. Supabase returns { data, error }, many REST APIs wrap results as { items: [...] }, and an error response is an object with a message. Code that saves the whole response into state and then calls .map on it hits this error.
For other names, the message means the name points at the wrong thing. onSave is not a function usually means the parent never passed an onSave prop. When the name is an imported function, the import usually doesn’t match the export, or the library renamed it.
Common causes
- The code stores a whole API response, such as
{ data, error }or{ items: [...] }, and calls.mapon it. - An error response replaced the list in state, so the next render calls
.mapon an object. - The list arrived as a JSON string because the code skipped
res.json()orJSON.parse. - A callback prop like
onChangeoronSavewasn’t passed by the parent, or was passed under another name. - An import doesn’t match the export, or a library function was renamed in a newer version.
How to fix it
- Log the value right before the call, as in
console.log(typeof data, data), to see what it really is. - If it’s an object, pull out the array:
datafrom a Supabase result, or the field that holds the list, such asbody.items. - Check
res.okand theerrorfield before saving a response into state, so an error never replaces the list. - If an API can return different shapes, check
Array.isArray(value)where the data enters your app. - For a missing callback prop, pass it from the parent, or mark it optional and call it with
onSave?.().
Example fix
type Todo = { id: string; title: string };
// Supabase returns { data, error }. The list is in data.
const { data, error } = await supabase.from('todos').select('id, title');
if (error) throw error;
const todos: Todo[] = data ?? [];
// REST APIs often wrap the list too.
const res = await fetch('https://api.example.com/todos');
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const body: { items: Todo[] } = await res.json();
const titles = [...todos, ...body.items].map((todo) => todo.title);Related errors
All errorsCannot read properties of undefined
The code asked for a property of a value that doesn’t exist yet, usually data that hasn’t loaded or a field the API didn’t return.
Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Your code expected JSON, but the server sent back an HTML page, usually a 404 page or your app’s own index.html.
Element type is invalid
A JSX tag pointed at undefined or an object instead of a component, almost always because an import doesn’t match how the file exports it.
X is not defined
The code used a name JavaScript can’t find anywhere, usually because of a missing import, a typo, or a Node-only global like process in the browser.
Build with an agent that checks its work
The Layerwise agent clicks through the live preview and reads the console, so it catches errors before you do.