karatelabs/karate · error · JsErrorException
groupBy callback is not a function
Error message
groupBy callback is not a function
What it means
GroupByImpl.run throws this TypeError when the callback argument is not a callable (not a JsCallable). groupBy needs a key-selector function (or a property name in property-mode resolved elsewhere), so a non-function callback cannot produce group keys.
Solutions
- Pass an actual function: `groupBy(items, item => item.key)`
- If you meant property-mode, use the property-mode entry point with the property name string
- Check the callback identifier isn't undefined (typo, wrong scope)
- Remove `()` if you accidentally invoked the callback instead of passing it
Example fix
// before groupBy(items, 'typeKey'); // string in function mode // after groupBy(items, item => item.typeKey);
Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof callback !== 'function') throw new Error('callback must be a function'); Type guard
function isFn(x) { return typeof x === 'function'; } Try / catch
try { groupBy(items, cb); } catch (e) { if (String(e).includes('not a function')) { /* fix callback arg */ } else { throw e; } } Prevention
- Never invoke the callback when passing it (no trailing ())
- Use property-mode API for string property keys
- Check identifiers for typos with lint
When it happens
Trigger: Passing a non-function as the second argument: a string in function-mode, an undefined variable, the result of calling the function instead of passing it (`cb(x)` vs `cb`), or a non-callable object.
Common situations: Typo where the callback name is undefined; forgetting that property-mode uses a different call shape so a string lands in the function-mode branch; arrow function vs invocation confusion.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- groupBy called with null or undefined items
- Map.prototype.forEach: callback is not a function
- filter() needs two arguments: list and function
- forEach() needs two arguments: collection and function
- onStdOut requires a function argument
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/e74cb3fedf5cf9ca.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/GroupByImpl.java:68
this.key = key;
}
}
/**
* Walks {@code items} via the spec iterator protocol, invokes
* {@code callback(value, k)} for each element, coerces the return value
* into a key per {@code propertyMode} (true → ToPropertyKey, false →
* -0 → +0 normalize), and accumulates values into groups in
* first-seen-key order. Group key equality uses {@link Terms#sameValue}
* (matches spec for the Map.groupBy case; for property-mode the keys are
* always strings and SameValue collapses to equals).
*/
static List<Group> run(Object items, Object callback, boolean propertyMode, Context context) {
if (items == null || items == Terms.UNDEFINED) {
throw JsErrorException.typeError("groupBy called with null or undefined items");
}
if (!(callback instanceof JsCallable cb)) {
throw JsErrorException.typeError("groupBy callback is not a function");
}
CoreContext cc = context instanceof CoreContext c ? c : null;
JsIterator iter = IterUtils.getIterator(items, context);
List<Group> groups = new ArrayList<>();
long k = 0;
while (iter.hasNext()) {
Object value = iter.next();
Object rawKey = cb.call(context, new Object[]{value, (double) k});
// IfAbruptCloseIterator: a callback that threw via context.error
// ends iteration without re-grouping. Surface the same error to
// our caller (already on cc.error).
if (cc != null && cc.isError()) {
return groups;
}
Object key;
if (propertyMode) {
// Spec ToPropertyKey — dispatches JS toString for ObjectLike values.
key = Terms.toPropertyKey(rawKey, cc);View on GitHub (pinned to a22eb90246)