{"record":{"id":"853df7129286fa5d","repo":"karatelabs/karate","slug":"expecting-function","errorCode":null,"errorMessage":": Expecting function","messagePattern":": Expecting function","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsObjectPrototype.java","lineNumber":130,"sourceCode":"        // IsCallable(getter/setter) on define*, then ToPropertyKey(P).\n        install(\"__defineGetter__\", 2, (ctx, args) -> defineAccessor(ctx, args, true));\n        install(\"__defineSetter__\", 2, (ctx, args) -> defineAccessor(ctx, args, false));\n        install(\"__lookupGetter__\", 1, (ctx, args) -> lookupAccessor(ctx, args, true));\n        install(\"__lookupSetter__\", 1, (ctx, args) -> lookupAccessor(ctx, args, false));\n        // Spec §20.1.3.1: Object.prototype.constructor === Object — resolved\n        // per access against the reading Engine's constructor instance.\n        installConstructor(\"Object\");\n    }\n\n    private static Object defineAccessor(Context context, Object[] args, boolean isGetter) {\n        String label = isGetter\n                ? \"Object.prototype.__defineGetter__\"\n                : \"Object.prototype.__defineSetter__\";\n        Object thisObj = context.getThisObject();\n        Terms.requireObjectCoercible(thisObj, label);\n        Object fn = args.length < 2 ? Terms.UNDEFINED : args[1];\n        if (!(fn instanceof JsCallable callable)) {\n            throw JsErrorException.typeError(label + \": Expecting function\");\n        }\n        // ToPropertyKey runs AFTER IsCallable per spec — the getter-non-callable\n        // test asserts the key's toString is never called when the function\n        // arg is rejected.\n        String key = args.length == 0 ? \"undefined\" : Terms.toPropertyKey(args[0]);\n        Map<String, Object> desc = new LinkedHashMap<>();\n        desc.put(isGetter ? \"get\" : \"set\", callable);\n        desc.put(\"enumerable\", true);\n        desc.put(\"configurable\", true);\n        JsObjectConstructor objectConstructor =\n                (JsObjectConstructor) context.getEngine().builtinConstructor(\"Object\");\n        objectConstructor.defineProperty(context, new Object[]{thisObj, key, desc});\n        return Terms.UNDEFINED;\n    }\n\n    private static Object lookupAccessor(Context context, Object[] args, boolean isGetter) {\n        String label = isGetter\n                ? \"Object.prototype.__lookupGetter__\"","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsObjectPrototype.java#L112-L148","documentation":"Object.prototype.__defineGetter__ / __defineSetter__ require the second argument to be a callable function. When it is not (missing, undefined, or any non-callable), a TypeError labelled with the method name is thrown. Per spec, IsCallable is checked before the key is coerced, so an object with a throwing toString is still rejected based on the function argument first.","triggerScenarios":"obj.__defineGetter__('x') with no function argument; obj.__defineGetter__('x', notAFunction) such as a value, null, or a string.","commonSituations":"Legacy __defineGetter__ code ported from old scripts where the getter was a variable that became undefined; copy/paste from code using defineProperty where argument positions differ.","solutions":["Pass an actual function: obj.__defineGetter__('x', () => this._x)","Migrate to the modern equivalent: Object.defineProperty(obj, 'x', { get: fn, configurable: true, enumerable: true })","Guard with typeof fn === 'function' before calling","Check argument order — for defineProperty the descriptor holds the getter; for __defineGetter__ it is arg 2"],"exampleFix":"// before\nobj.__defineGetter__('x', getterName); // getterName is undefined\n// after\nobj.__defineGetter__('x', function () { return this._x; });","handlingStrategy":"type-guard","validationCode":"if (typeof fn !== 'function') throw new TypeError('__defineGetter__/__defineSetter__ expects a function');","typeGuard":"function isCallable(v) { return typeof v === 'function'; }","tryCatchPattern":"try { obj.__defineGetter__(key, fn); } catch (e) { if (String(e.message).includes('Expecting function')) Object.defineProperty(obj, key, { get: defaultGetter, configurable: true }); else throw e; }","preventionTips":["Migrate legacy __defineGetter__/__defineSetter__ to Object.defineProperty","Never rely on a variable that may be undefined as the accessor argument","Remember IsCallable runs before key coercion — validate fn first"],"tags":["javascript","legacy","accessor","definegetter"],"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"}