karatelabs/karate · error · JsErrorException
: Expecting function
Error message
: Expecting function
What it means
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.
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
Example fix
// before
obj.__defineGetter__('x', getterName); // getterName is undefined
// after
obj.__defineGetter__('x', function () { return this._x; }); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof fn !== 'function') throw new TypeError('__defineGetter__/__defineSetter__ expects a function'); Type guard
function isCallable(v) { return typeof v === 'function'; } Try / catch
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; } Prevention
- 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
When it happens
Trigger: obj.__defineGetter__('x') with no function argument; obj.__defineGetter__('x', notAFunction) such as a value, null, or a string.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid property descriptor. Cannot both specify accessors…
- Getter must be a function
- Setter must be a function
- ' ' was defined without a getter
- ' ' was defined without a setter
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/853df7129286fa5d.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsObjectPrototype.java:130
// IsCallable(getter/setter) on define*, then ToPropertyKey(P).
install("__defineGetter__", 2, (ctx, args) -> defineAccessor(ctx, args, true));
install("__defineSetter__", 2, (ctx, args) -> defineAccessor(ctx, args, false));
install("__lookupGetter__", 1, (ctx, args) -> lookupAccessor(ctx, args, true));
install("__lookupSetter__", 1, (ctx, args) -> lookupAccessor(ctx, args, false));
// Spec §20.1.3.1: Object.prototype.constructor === Object — resolved
// per access against the reading Engine's constructor instance.
installConstructor("Object");
}
private static Object defineAccessor(Context context, Object[] args, boolean isGetter) {
String label = isGetter
? "Object.prototype.__defineGetter__"
: "Object.prototype.__defineSetter__";
Object thisObj = context.getThisObject();
Terms.requireObjectCoercible(thisObj, label);
Object fn = args.length < 2 ? Terms.UNDEFINED : args[1];
if (!(fn instanceof JsCallable callable)) {
throw JsErrorException.typeError(label + ": Expecting function");
}
// ToPropertyKey runs AFTER IsCallable per spec — the getter-non-callable
// test asserts the key's toString is never called when the function
// arg is rejected.
String key = args.length == 0 ? "undefined" : Terms.toPropertyKey(args[0]);
Map<String, Object> desc = new LinkedHashMap<>();
desc.put(isGetter ? "get" : "set", callable);
desc.put("enumerable", true);
desc.put("configurable", true);
JsObjectConstructor objectConstructor =
(JsObjectConstructor) context.getEngine().builtinConstructor("Object");
objectConstructor.defineProperty(context, new Object[]{thisObj, key, desc});
return Terms.UNDEFINED;
}
private static Object lookupAccessor(Context context, Object[] args, boolean isGetter) {
String label = isGetter
? "Object.prototype.__lookupGetter__"View on GitHub (pinned to a22eb90246)