{"record":{"id":"e74cb3fedf5cf9ca","repo":"karatelabs/karate","slug":"groupby-callback-is-not-a-function","errorCode":null,"errorMessage":"groupBy callback is not a function","messagePattern":"groupBy callback is not a function","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/GroupByImpl.java","lineNumber":68,"sourceCode":"            this.key = key;\n        }\n    }\n\n    /**\n     * Walks {@code items} via the spec iterator protocol, invokes\n     * {@code callback(value, k)} for each element, coerces the return value\n     * into a key per {@code propertyMode} (true → ToPropertyKey, false →\n     * -0 → +0 normalize), and accumulates values into groups in\n     * first-seen-key order. Group key equality uses {@link Terms#sameValue}\n     * (matches spec for the Map.groupBy case; for property-mode the keys are\n     * always strings and SameValue collapses to equals).\n     */\n    static List<Group> run(Object items, Object callback, boolean propertyMode, Context context) {\n        if (items == null || items == Terms.UNDEFINED) {\n            throw JsErrorException.typeError(\"groupBy called with null or undefined items\");\n        }\n        if (!(callback instanceof JsCallable cb)) {\n            throw JsErrorException.typeError(\"groupBy callback is not a function\");\n        }\n        CoreContext cc = context instanceof CoreContext c ? c : null;\n        JsIterator iter = IterUtils.getIterator(items, context);\n        List<Group> groups = new ArrayList<>();\n        long k = 0;\n        while (iter.hasNext()) {\n            Object value = iter.next();\n            Object rawKey = cb.call(context, new Object[]{value, (double) k});\n            // IfAbruptCloseIterator: a callback that threw via context.error\n            // ends iteration without re-grouping. Surface the same error to\n            // our caller (already on cc.error).\n            if (cc != null && cc.isError()) {\n                return groups;\n            }\n            Object key;\n            if (propertyMode) {\n                // Spec ToPropertyKey — dispatches JS toString for ObjectLike values.\n                key = Terms.toPropertyKey(rawKey, cc);","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/GroupByImpl.java#L50-L86","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ngroupBy(items, 'typeKey'); // string in function mode\n// after\ngroupBy(items, item => item.typeKey);","handlingStrategy":"type-guard","validationCode":"if (typeof callback !== 'function') throw new Error('callback must be a function');","typeGuard":"function isFn(x) { return typeof x === 'function'; }","tryCatchPattern":"try { groupBy(items, cb); } catch (e) { if (String(e).includes('not a function')) { /* fix callback arg */ } else { throw e; } }","preventionTips":["Never invoke the callback when passing it (no trailing ())","Use property-mode API for string property keys","Check identifiers for typos with lint"],"tags":["javascript","groupby","typeerror","callback","not-a-function"],"backgroundTag":"type-mismatch","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}