karatelabs/karate · error · JsErrorException

Map.prototype.forEach: callback is not a function

Error message

Map.prototype.forEach: callback is not a function

What it means

ES Map.prototype.forEach compliance check: the first argument must be a callable callback that receives (value, key, map), but it was absent or not a function. Fix by passing an actual function to Map.prototype.forEach.

Solutions

  1. Pass an actual function: `map.forEach((v, k) => {...})`
  2. Check spelling of the callback variable before the call
  3. Replace non-function placeholders with a no-op `() => {}` if iteration is intentionally skipped
  4. Validate the callback exists when it comes from dynamic code

Example fix

// before
map.forEach('logEach'); // TypeError: callback is not a function
// after
map.forEach((v, k) => karate.log(k, v));
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof cb !== 'function') { throw new Error('forEach needs a function callback'); }

Type guard

function isFn(x) { return typeof x === 'function'; }

Try / catch

try {
  m.forEach(cb);
} catch (e) {
  if (String(e.message).includes('callback is not a function')) {
    m.forEach(() => {}); // or surface a clear config error
  } else throw e;
}

Prevention

When it happens

Trigger: `map.forEach()` with no args; `map.forEach(undefined)`; passing a string/number/object instead of a function; a misspelled function name evaluating to undefined (`map.forEach(callbac)`).

Common situations: Typos in callback names; leaving placeholder args during refactor; passing config values (like a callback name string from JSON) instead of actual functions.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsMapPrototype.java:99

    }

    private Object has(Context context, Object[] args) {
        return asMap(context).hasKey(args.length > 0 ? args[0] : Terms.UNDEFINED);
    }

    private Object delete(Context context, Object[] args) {
        return asMap(context).deleteKey(args.length > 0 ? args[0] : Terms.UNDEFINED);
    }

    private Object clear(Context context, Object[] args) {
        asMap(context).clearAll();
        return Terms.UNDEFINED;
    }

    private Object forEach(Context context, Object[] args) {
        JsMap m = asMap(context);
        if (args.length == 0 || !(args[0] instanceof JsCallable cb)) {
            throw JsErrorException.typeError("Map.prototype.forEach: callback is not a function");
        }
        // Spec: forEach walks the live entry list. Entries appended during iteration
        // are visited; deletions ahead of the cursor are skipped naturally because the
        // cursor advances past them.
        int cursor = 0;
        while (cursor < m.entries.size()) {
            Iterator<Map.Entry<Object, Object>> it = m.entries.entrySet().iterator();
            for (int i = 0; i < cursor && it.hasNext(); i++) it.next();
            if (!it.hasNext()) break;
            Map.Entry<Object, Object> e = it.next();
            cb.call(context, new Object[]{e.getValue(), e.getKey(), m});
            cursor++;
        }
        return Terms.UNDEFINED;
    }

    private Object keys(Context context, Object[] args) {
        JsMap m = asMap(context);

View on GitHub (pinned to a22eb90246)