swc-project/swc · error · TypeError
Object is not iterable.
Error message
Object is not iterable.
What it means
`_ts_values` is the iteration helper emitted for `for...of` (and iterable destructuring) when TypeScript-style downlevel iteration is compiled by SWC. It accepts real iterables (`typeof o[Symbol.iterator] === 'function'`) or array-likes (`typeof o.length === 'number'`); anything else triggers `TypeError: Object is not iterable.`
Source
Thrown at crates/swc_ecma_transforms_base/src/helpers/generated/_ts_values.rs:25
local: "_ts_values",
import_path: "@swc/helpers/_/_ts_values",
#[cfg(feature = "inline-helpers")]
source: r#"function _ts_values(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) {
return m.call(o);
}
if (o && typeof o.length === "number") {
return {
next: function() {
if (o && i >= o.length) {
o = void 0;
}
return { value: o && o[i++], done: !o };
}
};
}
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}
"#,
#[cfg(feature = "inline-helpers")]
deps: super::HelperBitmap::from_bits(0x00000001000000000000000000000000),
};
#[cfg(feature = "inline-helpers")]
pub fn stmts() -> &'static [swc_ecma_ast::Stmt] {
static STMTS: once_cell::sync::Lazy<Vec<swc_ecma_ast::Stmt>> =
once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path));
&STMTS
}
View on GitHub (pinned to 5176682b65)
Solutions
- Use `Object.entries(obj)` / `Object.keys` / `Object.values` for plain-object iteration.
- Normalize before the loop: `for (const x of Array.from(obj))` when the value is array-like.
- Add an iterator to your custom class: `*[Symbol.iterator]() { ... }`.
- Fix the data source to hand the loop an actual array/iterable.
Example fix
// before
for (const item of config) {} // config = { a: 1 }
// TypeError: Object is not iterable.
// after
for (const [key, value] of Object.entries(config ?? {})) {} Defensive patterns
Strategy: type-guard
Validate before calling
// Mirror _ts_values: accept iterables or array-likes before for-of.
const isIterableOrArrayLike = (v) =>
v != null &&
(typeof v[Symbol.iterator] === 'function' || typeof v.length === 'number');
const source = await getData();
if (!isIterableOrArrayLike(source)) throw new TypeError(`expected iterable, got ${typeof source}`);
for (const x of source) { /* ... */ } Type guard
const isIterableOrArrayLike = <T>(v: unknown): v is Iterable<T> | ArrayLike<T> =>
v != null &&
(typeof (v as Iterable<T>)[Symbol.iterator] === 'function' ||
typeof (v as ArrayLike<T>).length === 'number'); Try / catch
try {
for (const x of obj) { handle(x); }
} catch (err) {
if (err instanceof TypeError && /not iterable/.test(err.message)) {
for (const value of Object.values(obj ?? {})) { handle(value); }
} else throw err;
} Prevention
- Use `Object.entries/keys/values` for plain-object iteration — never `for...of` directly.
- Validate external payloads with a schema so shape changes (array to object) fail early with context.
- Give custom collections a `*[Symbol.iterator]()` method if they should participate in `for...of`.
When it happens
Trigger: `for (const x of obj)` where `obj` is a plain object (no `[Symbol.iterator]`, no `.length`) in output compiled with downlevel iteration helpers — typically TS with target below ES2015 or `downlevelIteration` semantics.
Common situations: Iterating a plain object expecting entries instead of using `Object.entries`; an API changing an array response to an object; DOM/custom collections without iterator support; Map/Set confused with plain objects.
Related errors
- Invalid attempt to destructure non-iterable instance. In ord
- Invalid attempt to spread non-iterable instance. In order to
- Duplicated element (${elements[j].key})
- Cannot destructure ${o}
- Object expected.
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/ecb55ecd40d5df4b.
Report an issue: GitHub.