karatelabs/karate · error · JsErrorException
callback is not a function
Error message
callback is not a function
What it means
Array iteration/reduce/sort methods require their first argument to be a callable callback per spec. Karate's requireCallable throws TypeError '<methodName> callback is not a function' when args[0] is missing or not a JsCallable, keeping messages like 'Array.prototype.map called on non-callable' spec-shaped.
Solutions
- Pass an actual function: arr.map(x => x * 2)
- Check the variable holds a function before the call: typeof cb === 'function'
- Fix typos or failed imports that left the callback undefined
- Use a no-op or identity function when a callback is genuinely unneeded
Example fix
// before arr.map(callback); // callback is undefined // after if (typeof callback !== 'function') callback = x => x; arr.map(callback);
Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof cb !== 'function') throw new Error('callback must be a function'); Type guard
function isCallable(x) { return typeof x === 'function'; } Try / catch
try { return arr.map(cb); } catch (e) { if (String(e.message).includes('callback is not a function')) return arr; throw e; } Prevention
- Check typeof fn === 'function' before passing callbacks
- Watch for typos in callback variable names
- Never pass sort-style keys to map/filter and vice versa
- Default optional callbacks: cb = cb || (x => x)
When it happens
Trigger: arr.map() with no arguments; arr.filter('string'); arr.sort(42); passing a non-function (null, object, number) as the callback to map/filter/every/some/forEach/find/reduce/sort etc.
Common situations: Typo'd callback names (arr.map(calback)); variables holding non-functions because a lookup failed; calling methods with stale signatures after refactors; confusing sort (comparator) and map (callback).
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Array.from requires an iterable or array-like object, not
- is not iterable
- Cannot assign to read only property 'length' of object…
- Array.prototype.* called on null or undefined
- Reduce of empty array with no initial value
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/932672d76bf02248.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsArrayPrototype.java:476
throw JsErrorException.typeError("Array.prototype.* called on null or undefined");
}
return o;
}
private static final Object[] EMPTY_ARGS = new Object[0];
/** Spec {@code IsCallable} guard — every {@code Array.prototype.*}
* iteration method begins with a TypeError when the supplied callbackfn
* is not a function (spec FindViaPredicate / map / filter / forEach /
* every / some / reduce / reduceRight / flatMap step 1). The method
* name flows into the error so test262's
* {@code Array.prototype.map called on non-callable} style assertions
* carry the spec context. */
private static JsCallable requireCallable(Object[] args, String methodName) {
if (args.length > 0 && args[0] instanceof JsCallable callable) {
return callable;
}
throw JsErrorException.typeError(methodName + " callback is not a function");
}
/** Spec {@code Call(callbackfn, thisArg, …)} hookup for the iteration
* methods. When {@code methodArgs[thisArgIdx]} is supplied, wraps
* {@code inner} so each invocation temporarily binds the user-supplied
* {@code thisArg} as the call-site's {@code this} via save/restore on
* the live {@link CoreContext} — {@code Array.prototype.map.call(arr,
* fn, ctx)}'s {@code fn} then sees {@code this === ctx} per §23.1.3.21.
* Save/restore (rather than allocating a child context) keeps error
* propagation simple — the user function's throw lands on the same
* context the iteration loop checks via {@link CoreContext#isError()},
* no intermediate frame to {@code updateFrom}.
* <p>
* When {@code thisArg} is absent (caller passed fewer args), spec wants
* {@code Call(fn, undefined, …)}; for sloppy-mode callbacks ToObject
* then promotes {@code undefined} to {@code globalThis}. We don't model
* the strict / sloppy split, so when {@code thisArg} is absent we
* leave the existing {@code this} alone — keeps idiomaticView on GitHub (pinned to a22eb90246)