{"record":{"id":"932672d76bf02248","repo":"karatelabs/karate","slug":"callback-is-not-a-function","errorCode":null,"errorMessage":" callback is not a function","messagePattern":" callback is not a function","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsArrayPrototype.java","lineNumber":476,"sourceCode":"            throw JsErrorException.typeError(\"Array.prototype.* called on null or undefined\");\n        }\n        return o;\n    }\n\n    private static final Object[] EMPTY_ARGS = new Object[0];\n\n    /** Spec {@code IsCallable} guard — every {@code Array.prototype.*}\n     *  iteration method begins with a TypeError when the supplied callbackfn\n     *  is not a function (spec FindViaPredicate / map / filter / forEach /\n     *  every / some / reduce / reduceRight / flatMap step 1). The method\n     *  name flows into the error so test262's\n     *  {@code Array.prototype.map called on non-callable} style assertions\n     *  carry the spec context. */\n    private static JsCallable requireCallable(Object[] args, String methodName) {\n        if (args.length > 0 && args[0] instanceof JsCallable callable) {\n            return callable;\n        }\n        throw JsErrorException.typeError(methodName + \" callback is not a function\");\n    }\n\n    /** Spec {@code Call(callbackfn, thisArg, …)} hookup for the iteration\n     *  methods. When {@code methodArgs[thisArgIdx]} is supplied, wraps\n     *  {@code inner} so each invocation temporarily binds the user-supplied\n     *  {@code thisArg} as the call-site's {@code this} via save/restore on\n     *  the live {@link CoreContext} — {@code Array.prototype.map.call(arr,\n     *  fn, ctx)}'s {@code fn} then sees {@code this === ctx} per §23.1.3.21.\n     *  Save/restore (rather than allocating a child context) keeps error\n     *  propagation simple — the user function's throw lands on the same\n     *  context the iteration loop checks via {@link CoreContext#isError()},\n     *  no intermediate frame to {@code updateFrom}.\n     *  <p>\n     *  When {@code thisArg} is absent (caller passed fewer args), spec wants\n     *  {@code Call(fn, undefined, …)}; for sloppy-mode callbacks ToObject\n     *  then promotes {@code undefined} to {@code globalThis}. We don't model\n     *  the strict / sloppy split, so when {@code thisArg} is absent we\n     *  leave the existing {@code this} alone — keeps idiomatic","sourceCodeStart":458,"sourceCodeEnd":494,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsArrayPrototype.java#L458-L494","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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"],"exampleFix":"// before\narr.map(callback); // callback is undefined\n// after\nif (typeof callback !== 'function') callback = x => x;\narr.map(callback);","handlingStrategy":"type-guard","validationCode":"if (typeof cb !== 'function') throw new Error('callback must be a function');","typeGuard":"function isCallable(x) { return typeof x === 'function'; }","tryCatchPattern":"try { return arr.map(cb); } catch (e) { if (String(e.message).includes('callback is not a function')) return arr; throw e; }","preventionTips":["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)"],"tags":["javascript","array","callback","type-error"],"backgroundTag":"invalid-argument-value","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"}