Introduction
When you see TypeError: x is not iterable in JavaScript, it means your code tried to loop over, spread, or destructure something (x) that isn’t a valid iterable. In simple words: you treated it like a list or a string (something you can go through item by item), but it wasn't.
An iterable in JavaScript is something that has a special method named [Symbol.iterator]() that lets JavaScript get elements one by one. Built-in iterables include arrays, strings, Maps, Sets, generator results, etc.
So when you do things like for (let v of x), or [...x], or destructure as const [a, b] = x, JavaScript checks if x is iterable. If not, it throws the “not iterable” TypeError.
Detailed causes and how to recognize them
1. Looping over a plain object (using for…of)
Plain objects (like { key: value }) are not iterable by default. So:
const obj = { name: "Alice", age: 25 };
for (const x of obj) {
console.log(x);
}
// → TypeError: obj is not iterable
Why? Because objects don’t implement the iteration protocol ([Symbol.iterator]). They are key-value stores, not ordered lists.
How to fix / workaround:
Use Object.keys(obj) to get an array of keys, then loop over that.
Use Object.values(obj) to get values as an array.
Use Object.entries(obj) to get key–value pairs as arrays.
Example?
const obj = { name: "Alice", age: 25 };
for (const key of Object.keys(obj)) {
console.log(key, obj[key]);
}
for (const [k, v] of Object.entries(obj)) {
console.log(k, v);
}
2. Using spread syntax (...) or array destructuring on non-iterables
Spread syntax and destructuring expect an iterable. If you try to spread a non-iterable:
const obj = { a: 1, b: 2 };
const arr = [...obj]; // Error: obj is not iterable
Or destructure wrongly
const data = { x: 10, y: 20 };
const [a, b] = data; // Error: data is not iterable
Fix / safe approach
Only spread arrays, strings, or other iterables.
If you have an object, convert it first into an iterable form (e.g. Object.values(obj) or Object.entries(obj)).
Use proper destructuring: for objects use {} destructuring:
const { x, y } = data; // Correct for object
Or if inside the object there’s an array
const data = { items: [5, 10] };
const { items: [first, second] } = data; // OK
3. Passing undefined, null, or missing data to loops/functions
Sometimes you think x is an array, but it's actually undefined or null. That also leads to “is not iterable”.
Example
let arr = null;
for (const v of arr) {
console.log(v);
}
// → TypeError: arr is not iterable
Or
const [a, b] = undefined; // Error: undefined is not iterable
How to guard against this
Check before iterating
if (x != null && typeof x[Symbol.iterator] === "function") {
for (const v of x) {
// safe iteration
}
} else {
console.warn("x is not iterable:", x);
}
Use defaults/fallback values
const arr = maybeArray || [];
for (const v of arr) {
console.log(v);
}
In function parameters, give a default
function process(list = []) {
for (const item of list) {
console.log(item);
}
}
Or check with Array.isArray(x) before using spread/destructuring.
4. Not invoking a generator function (forgetting ())
Generator functions (declared with function*) return iterators when invoked. If you forget to call them:
function* gen() {
yield 1;
yield 2;
}
// Wrong:
for (const v of gen) {
console.log(v);
}
// → TypeError: gen is not iterable
// Correct:
for (const v of gen()) {
console.log(v); // 1, then 2
}
So always call the generator (with ()) to get an iterable object.
5. Passing bad data to functions expecting iterables (e.g. Promise.all, Array.from, Set(...))
Some JavaScript APIs assume you pass an iterable. If you pass a plain object or something that is not iterable, you'll get the error:
const obj = { name: "Alice" };
Promise.all(obj); // Error: obj is not iterable
Array.from(obj); // Error: obj is not iterable
new Set(obj); // Error
Fix
Ensure the argument is an array or iterable.
If you must accept non-iterable input, validate or convert it:
if (x && typeof x[Symbol.iterator] === "function") {
return Promise.all(x);
} else {
console.error("Expected iterable for Promise.all, got:", x);
return Promise.resolve([]); // fallback
}
6. Debugging the error (how to find where it occurs)
When you see TypeError: x is not iterable, you need to find which x is causing the error.
Steps to debug
Add console.log just before the loop, spread, or function call:
console.log("Value of x:", x, "type:", typeof x);
for (const v of x) {
console.log(v);
}
The log will often show you something like x = { … } (an object), or x = undefined or x = null — that tells you the mismatch.
In stack trace, see which file / line is triggering it. Then inspect data flow: where did x come from? API? Props? Function return?
Use Developer Tools (browser console) or breakpoints to step through and inspect.
If in a React / Node / Angular project, sometimes values coming from API or state are wrongly typed — check those sources.
By doing this, you’ll understand exactly which variable is non-iterable and why.
Summary
When you see “TypeError: x is not iterable” in JavaScript, it means your code tried to treat x like something you can loop over or spread (an iterable), but it wasn’t. To fix it:
Know which types are iterable (arrays, strings, Map, Set, generators) and which are not by default (plain objects, undefined, null).
If you have an object, convert it via Object.keys, Object.values, or Object.entries before iterating.
Guard against null or undefined by checking or giving default values.
Use the correct destructuring syntax for arrays or objects.
Invoke generator functions correctly.
Validate inputs passed into functions like Promise.all or Array.from.
Debug using console.log or breakpoints to see the actual type and value of your variable.
By carefully validating and converting your data before using loops, spreads, or destructuring, you’ll avoid this common JavaScript error and make your code more robust in JS projects in India or anywhere. If you like, I can also craft a cheat sheet or template code optimized for React, Node.js or your environment. Do you want me to prepare that?