karatelabs/karate · error · JsErrorException (typeError)
Symbol.toPrimitive method is not callable
Error message
Symbol.toPrimitive method is not callable
What it means
When an object defines @@toPrimitive, the spec's GetMethod requires it to be callable. Terms.java throws this TypeError when Symbol.toPrimitive exists but is not a function (e.g. a number, string, or plain object), instead of ignoring it.
Solutions
- Make @@toPrimitive a function: { [Symbol.toPrimitive]: (hint) => ... }
- Remove the property if custom conversion isn't intended, letting valueOf/toString handle coercion
- Guard in library code: check typeof obj[Symbol.toPrimitive] === 'function' before relying on it
Example fix
// before
const o = { [Symbol.toPrimitive]: '42' };
// after
const o = { [Symbol.toPrimitive]: (hint) => '42' }; Defensive patterns
Strategy: validation
Validate before calling
const tp = obj[Symbol.toPrimitive];
if (tp !== undefined && typeof tp !== 'function') throw new Error('Symbol.toPrimitive must be callable'); Type guard
function hasCallableToPrimitive(o) { return o == null || typeof o[Symbol.toPrimitive] === 'function' || o[Symbol.toPrimitive] === undefined; } Try / catch
try { n = obj + 0; } catch (e) { if (String(e).includes('not callable')) n = Number(obj.valueOf ? obj.valueOf() : obj); else throw e; } Prevention
- Assign functions (not values) to Symbol.toPrimitive
- Don't build objects from raw JSON that might overwrite well-known symbols
- Type-check computed object literals in test scripts
When it happens
Trigger: An object in karate-js has a non-callable `Symbol.toPrimitive` member and is then used in arithmetic, comparison, or string coercion that triggers ToPrimitive with a hint.
Common situations: Typos like `{ [Symbol.toPrimitive]: 'number' }`, assigning the symbol itself instead of a function, or JSON/config data accidentally overwriting the well-known symbol property.
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
- Cannot convert a Symbol value to a string
- Cannot convert object to primitive value
- Date.prototype[@@toPrimitive] called on non-object
- a class declaration may not be the body of
- a function declaration may not be the body of
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/d959430b95630ccf.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/Terms.java:1345
return jp.getJavaValue();
}
if (value instanceof BigInteger || isPrimitive(value)) {
return value;
}
// ObjectLike (or Java-native types we wrap): run OrdinaryToPrimitive.
ObjectLike ol = (value instanceof ObjectLike) ? (ObjectLike) value : toObjectLike(value);
if (ol == null || context == null) {
// No prototype dispatch possible — return as-is and let the caller cope.
return value;
}
// Spec: @@toPrimitive (the well-known Symbol.toPrimitive method) takes precedence
// over OrdinaryToPrimitive's valueOf/toString dispatch. Hint passed verbatim
// ("string" | "number" | "default"). Result must be a primitive; an object result
// is a TypeError per spec. Set-but-not-callable is also a TypeError (GetMethod).
Object exotic = ol.getMember("@@toPrimitive");
if (exotic != null && exotic != UNDEFINED) {
if (!(exotic instanceof JsCallable jsc)) {
throw JsErrorException.typeError("Symbol.toPrimitive method is not callable");
}
CoreContext callCtx = new CoreContext(context, null, null);
callCtx.thisObject = ol;
String hintArg = hint == null ? "default" : hint;
Object r = jsc.call(callCtx, new Object[]{hintArg});
if (callCtx.isError()) {
context.updateFrom(callCtx);
return UNDEFINED;
}
if (r == null || r == UNDEFINED || isPrimitive(r) || r instanceof BigInteger) {
return r;
}
throw JsErrorException.typeError("Cannot convert object to primitive value");
}
return ordinaryToPrimitive(ol, hint, context);
}
/**View on GitHub (pinned to a22eb90246)