karatelabs/karate · error · JsErrorException

is not iterable

Error message

${describe(source)} is not iterable

What it means

IterUtils.getIterator implements GetIterator(source) per the ECMAScript spec (7.4.1). When the value passed to a for-of loop, spread, Array.from, or destructuring is null, undefined, or has no callable Symbol.iterator, tryGetIterator returns null and this TypeError is thrown. It exists to give JS scripts the same TypeError the spec mandates instead of a silent failure or Java NPE.

Solutions

  1. Guard the value before iterating: `if (response != undefined && response.length !== undefined)` or default it `var list = response || []`.
  2. Fix the data source so the API/JSON path returns an array instead of null.
  3. If iterating a custom object, give it a Symbol.iterator method returning an iterator object with a callable next().
  4. Catch the TypeError in JS (try/catch) if absence of data is an expected case.

Example fix

// before
for (var item of response.items) { ... }
// after
var items = response.items == null ? [] : response.items;
for (var item of items) { ... }
Defensive patterns

Strategy: validation

Validate before calling

if (source == null || typeof source[Symbol.iterator] !== 'function') {
  throw new TypeError('value is not iterable: ' + String(source));
}

Type guard

function isIterable(v) { return v != null && typeof v[Symbol.iterator] === 'function'; }

Try / catch

try { for (var x of source) { ... } } catch (e) { if (String(e).indexOf('not iterable') !== -1) { source = []; } else { throw e; } }

Prevention

When it happens

Trigger: Calling getIterator (directly or via for-of/spread/Array.from/destructuring) with null or undefined, or with an object that lacks a callable Symbol.iterator property, e.g. `for (var x of null)`, `[...5]`, or spreading a plain non-iterable object.

Common situations: A JSON path or API response returned null/undefined instead of an array (empty result set, missing field in response), a function that should return an array returned a scalar, or a Java object was passed into JS and karate did not auto-wrap it as iterable.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/081ebdf829ddaff4. Report an issue: GitHub.

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/IterUtils.java:77

     * detached from an iterable receiver.
     */
    public static final JsCallable SYMBOL_ITERATOR_METHOD = (ctx, args) -> {
        Object thisObj = ctx.getThisObject();
        JsIterator iter = getIterator(thisObj, ctx);
        return toIteratorObject(iter);
    };

    private IterUtils() {
    }

    /**
     * GetIterator(source) per spec 7.4.1. Throws {@link JsErrorException}
     * (TypeError) if {@code source} is null/undefined or otherwise not iterable.
     */
    public static JsIterator getIterator(Object source, Context context) {
        JsIterator iter = tryGetIterator(source, context);
        if (iter == null) {
            throw JsErrorException.typeError(describe(source) + " is not iterable");
        }
        return iter;
    }

    /**
     * Like {@link #getIterator} but returns null instead of throwing — for callers
     * that need to gate behavior on iterability without forcing a TypeError.
     */
    @SuppressWarnings("unchecked")
    public static JsIterator tryGetIterator(Object source, Context context) {
        if (source == null || source == Terms.UNDEFINED) {
            return null;
        }
        if (source instanceof JsArray jsArray) {
            // The dense fast path is only valid while the array still resolves
            // the untampered built-in @@iterator. A deleted or replaced
            // Array.prototype[@@iterator] (or an own-property override) must be
            // honored — TypeError on deletion, the user's method on override.

View on GitHub (pinned to a22eb90246)