karatelabs/karate · error · JsErrorException
is not a constructor
Error message
${node.getTextIncludingWhitespace()} is not a constructor What it means
invokeCallable throws this TypeError when `new X(...)` is used with a value that, while callable, is not constructable (JsCallable.isConstructable() is false) — mirroring the ECMAScript rule that e.g. arrow functions, methods, and built-ins like Math.* cannot be constructors. The message includes the source text of the callee expression.
Solutions
- Remove `new` and call the function normally if it returns the object you need
- Convert the arrow function/method to a regular `function` or `class` if construction is intended
- If it's a built-in, use its factory API instead of `new` (e.g. Array.isArray vs new-wrapper patterns)
- Check the variable actually refers to a constructable class and not an instance or helper
Example fix
// before
const Point = (x, y) => ({ x, y });
const p = new Point(1, 2); // not a constructor
// after
const Point = (x, y) => ({ x, y });
const p = Point(1, 2); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof C === 'function' && !C.prototype || isArrow(C)) { /* call without new */ } Type guard
function isConstructable(f) { try { return typeof f === 'function' && /^\s*(class|function)/.test(String(f)); } catch (e) { return false; } } Try / catch
try { var o = new C(); } catch (e) { if (String(e).includes('is not a constructor')) { o = C(); } else { throw e; } } Prevention
- Don't use new with arrow functions or methods
- Prefer class syntax when construction is intended
- Document which exported helpers are factories vs constructors
When it happens
Trigger: `new arrowFn()`, `new someObjectMethod()`, `new (() => 1)`, or `new` on class-less helpers / host-provided functions the engine marks non-constructable (karate built-ins, arrow callbacks defined in scripts).
Common situations: JS code written before the callee was refactored to an arrow function; using `new` by habit on helper functions; copying CommonJS/browser code that wrapped a constructor that karate models as a plain callable.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Class constructor cannot be invoked without 'new
- Constructor Map requires 'new'
- Constructor WeakMap requires 'new'
- Constructor WeakSet requires 'new'
- Cannot set property ' ' which has only a getter
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/feccb40cda159257.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/Interpreter.java:649
// Handles `a?.(args)` shape: REF_DOT_EXPR[base, FN_CALL_EXPR[?., (, args, )]].
// Per spec the chain head is the base (must be evaluated once); if nullish,
// short-circuit the entire call without evaluating the args. Goes through
// getCallable so a method-reference base (`a.b?.()`) keeps `a` as receiver.
private static Object evalOptionalCall(Node node, CoreContext context) {
Object o = PropertyAccess.getCallable(node.getFirst(), context);
Object receiver = context.callReceiver; // consume immediately (see field contract)
if (o == PropertyAccess.SHORT_CIRCUITED) return PropertyAccess.SHORT_CIRCUITED;
if (o == null || o == Terms.UNDEFINED) return PropertyAccess.SHORT_CIRCUITED;
Node callExpr = node.get(1); // FN_CALL_EXPR -> [?., (, FN_CALL_ARGS, )]
Node fnArgsNode = callExpr.get(2);
return invokeCallable(o, receiver, fnArgsNode, false, node.getFirst(), context);
}
private static Object invokeCallable(Object o, Object receiver, Node fnArgsNode,
boolean newKeyword, Node node, CoreContext context) {
if (o instanceof JsCallable callable) {
if (newKeyword && !callable.isConstructable()) {
throw JsErrorException.typeError(node.getTextIncludingWhitespace() + " is not a constructor");
}
if (!newKeyword && callable instanceof JsFunctionNode cf && cf.isClassConstructor) {
String n = cf.name == null || cf.name.isEmpty() ? "" : cf.name + " ";
throw JsErrorException.typeError("Class constructor " + n + "cannot be invoked without 'new'");
}
Object[] args = evalCallArgs(fnArgsNode, context);
// An argument that threw means there is no call to make. evalSuperCall already does
// this; every other call site did not, so `f(mustSucceed())` invoked f anyway.
if (context.isError()) {
return Terms.UNDEFINED;
}
// Convert JS types to Java types if JS/Java boundary:
// - undefined → null
// - JsValue (JsDate, etc.) → unwrapped via getJavaValue()
if (callable.isExternal()) {
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
if (arg == Terms.UNDEFINED) {View on GitHub (pinned to a22eb90246)