{"record":{"id":"ac0732645d1fc2bc","repo":"karatelabs/karate","slug":"map-prototype-getorinsertcomputed-callback-is-not-a-function","errorCode":null,"errorMessage":"Map.prototype.getOrInsertComputed: callback is not a function","messagePattern":"Map\\.prototype\\.getOrInsertComputed: callback is not a function","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsMapPrototype.java","lineNumber":162,"sourceCode":"        m.setValue(key, value);\n        return value;\n    }\n\n    /**\n     * Spec ES2025 upsert: {@code getOrInsertComputed(key, callbackfn)}. If the\n     * key is present, returns the existing value WITHOUT invoking the callback\n     * (does-not-evaluate-callbackfn-if-key-present.js). Otherwise calls\n     * {@code callbackfn(canonicalKey)} (canonical-key-passed-to-callback.js)\n     * and stores the result. Re-checks key presence after the callback returns\n     * so a callback that mutates the map can't leave a stale insert\n     * (overwrites-mutation-from-callbackfn.js).\n     */\n    private Object getOrInsertComputed(Context context, Object[] args) {\n        JsMap m = asMap(context);\n        Object key = args.length > 0 ? args[0] : Terms.UNDEFINED;\n        Object cb = args.length > 1 ? args[1] : Terms.UNDEFINED;\n        if (!(cb instanceof JsCallable callable)) {\n            throw JsErrorException.typeError(\"Map.prototype.getOrInsertComputed: callback is not a function\");\n        }\n        if (m.hasKey(key)) {\n            return m.getValue(key);\n        }\n        // Canonical key: spec normalizes -0 to +0 before invoking callback.\n        Object canonicalKey = JsMap.normalizeKey(key);\n        Object value = callable.call(context, new Object[]{canonicalKey});\n        // Spec: a callback that threw stops the operation. The engine signals\n        // throws via {@code cc.error}; bail without inserting so post-throw\n        // {@code map.has(key) === false} (check-state-after-callback-fn-throws.js).\n        CoreContext cc = context instanceof CoreContext c ? c : null;\n        if (cc != null && cc.isError()) {\n            return Terms.UNDEFINED;\n        }\n        // Java-null callback returns surface to JS as undefined. Re-checking\n        // map state after the callback returned: per spec, OVERWRITE any\n        // entry the callback inserted at the same key\n        // (overwrites-mutation-from-callbackfn.js).","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsMapPrototype.java#L144-L180","documentation":"`Map.prototype.getOrInsertComputed(key, callback)` (upsert proposal) invokes the callback only when the key is absent, but the callback itself must be a function. Karate throws this TypeError when args[1] is missing or not a JsCallable.","triggerScenarios":"`map.getOrInsertComputed('k')` without the callback; passing a value instead of a function (`map.getOrInsertComputed('k', 42)`); passing a function name string from config instead of the function itself.","commonSituations":"Confusing getOrInsertComputed with getOrInsert (which takes a plain value); refactors that swapped the two APIs; dynamically loaded callbacks that failed to resolve.","solutions":["Pass a function as the second argument: `map.getOrInsertComputed('k', () => compute())`","If you have a plain value, use `map.getOrInsert('k', value)` instead","Check that the callback variable resolves to a function, not its name/string"],"exampleFix":"// before\nmap.getOrInsertComputed('key', 42); // TypeError\n// after\nmap.getOrInsertComputed('key', () => 42);","handlingStrategy":"type-guard","validationCode":"if (typeof cb !== 'function') { throw new Error('getOrInsertComputed requires a function callback'); }","typeGuard":"function isFn(x) { return typeof x === 'function'; }","tryCatchPattern":"try {\n  m.getOrInsertComputed(key, cb);\n} catch (e) {\n  if (String(e.message).includes('callback is not a function')) {\n    m.getOrInsert(key, cb); // maybe a plain value was intended\n  } else throw e;\n}","preventionTips":["Remember: Computed variant takes a function, getOrInsert takes a value","Wrap lazily computed defaults: () => expensiveCompute()","Resolve dynamic callbacks before the call"],"tags":["javascript","map","callback","upsert"],"backgroundTag":"missing-required-argument","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}