{"record":{"id":"fc2f4e5220c3397b","repo":"karatelabs/karate","slug":"class-constructor-n-cannot-be-invoked-without-new","errorCode":null,"errorMessage":"Class constructor ${n}cannot be invoked without 'new'","messagePattern":"Class constructor (.+?)cannot be invoked without 'new'","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/Interpreter.java","lineNumber":653,"sourceCode":"    private static Object evalOptionalCall(Node node, CoreContext context) {\n        Object o = PropertyAccess.getCallable(node.getFirst(), context);\n        Object receiver = context.callReceiver; // consume immediately (see field contract)\n        if (o == PropertyAccess.SHORT_CIRCUITED) return PropertyAccess.SHORT_CIRCUITED;\n        if (o == null || o == Terms.UNDEFINED) return PropertyAccess.SHORT_CIRCUITED;\n        Node callExpr = node.get(1); // FN_CALL_EXPR -> [?., (, FN_CALL_ARGS, )]\n        Node fnArgsNode = callExpr.get(2);\n        return invokeCallable(o, receiver, fnArgsNode, false, node.getFirst(), context);\n    }\n\n    private static Object invokeCallable(Object o, Object receiver, Node fnArgsNode,\n                                          boolean newKeyword, Node node, CoreContext context) {\n        if (o instanceof JsCallable callable) {\n            if (newKeyword && !callable.isConstructable()) {\n                throw JsErrorException.typeError(node.getTextIncludingWhitespace() + \" is not a constructor\");\n            }\n            if (!newKeyword && callable instanceof JsFunctionNode cf && cf.isClassConstructor) {\n                String n = cf.name == null || cf.name.isEmpty() ? \"\" : cf.name + \" \";\n                throw JsErrorException.typeError(\"Class constructor \" + n + \"cannot be invoked without 'new'\");\n            }\n            Object[] args = evalCallArgs(fnArgsNode, context);\n            // An argument that threw means there is no call to make. evalSuperCall already does\n            // this; every other call site did not, so `f(mustSucceed())` invoked f anyway.\n            if (context.isError()) {\n                return Terms.UNDEFINED;\n            }\n            // Convert JS types to Java types if JS/Java boundary:\n            // - undefined → null\n            // - JsValue (JsDate, etc.) → unwrapped via getJavaValue()\n            if (callable.isExternal()) {\n                for (int i = 0; i < args.length; i++) {\n                    Object arg = args[i];\n                    if (arg == Terms.UNDEFINED) {\n                        args[i] = null;\n                    } else if (arg instanceof JsValue jv && !(arg instanceof JsPrimitive)) {\n                        // Unwrap JsValue (JsDate, JsUint8Array) but not JsPrimitive (Boolean/String/Number constructors)\n                        args[i] = jv.getJavaValue();","sourceCodeStart":635,"sourceCodeEnd":671,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/Interpreter.java#L635-L671","documentation":"Calling a class constructor as a plain function (no `new`) is a TypeError per ECMAScript; invokeCallable raises this when the callee is a JsFunctionNode whose isClassConstructor is true and newKeyword is false. The message includes the class name (with a trailing space when named).","triggerScenarios":"`MyClass()` instead of `new MyClass()`; calling a class constructor via call/apply-style plain invocation; super-adjacent mistakes where a helper invokes the constructor directly; evaluating `typeof`-style debug calls that invoke the class.","commonSituations":"Migrating ES5 function-constructors to class syntax while old call sites (without new) remain; dynamic dispatch tables storing classes and invoking them without new; minified/generated code losing the new.","solutions":["Add `new` at the call site: `new MyClass(...)`","If the call site is generic, branch on whether the value is a class before invoking","Keep ES5 function-constructors as plain functions if they must be callable without new","In dynamic/reflective host code, use the construct path rather than the plain-call path for classes"],"exampleFix":"// before\nconst c = MyClass(1, 2); // throws\n// after\nconst c = new MyClass(1, 2);","handlingStrategy":"type-guard","validationCode":"if (typeof MyClass !== 'function' || MyClass.toString().trim().startsWith('class')) { /* must use new */ }","typeGuard":"function isClassCtor(f) { return typeof f === 'function' && /^\\s*class\\s/.test(String(f)); }","tryCatchPattern":"try { const c = MyClass(); } catch (e) { if (String(e).includes(\"cannot be invoked without 'new'\")) { c = new MyClass(); } else { throw e; } }","preventionTips":["Always pair class declarations with new at call sites","When refactoring function-constructors to classes, grep all call sites for missing new","In dispatch tables, mark entries needing construction"],"tags":["javascript","class","constructor","typeerror","new"],"backgroundTag":"unsupported-operation","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"}