{"record":{"id":"feccb40cda159257","repo":"karatelabs/karate","slug":"node-gettextincludingwhitespace-is-not-a-constructor","errorCode":null,"errorMessage":"${node.getTextIncludingWhitespace()} is not a constructor","messagePattern":"(.+?) is not a constructor","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/Interpreter.java","lineNumber":649,"sourceCode":"    // Handles `a?.(args)` shape: REF_DOT_EXPR[base, FN_CALL_EXPR[?., (, args, )]].\n    // Per spec the chain head is the base (must be evaluated once); if nullish,\n    // short-circuit the entire call without evaluating the args. Goes through\n    // getCallable so a method-reference base (`a.b?.()`) keeps `a` as receiver.\n    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) {","sourceCodeStart":631,"sourceCodeEnd":667,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/Interpreter.java#L631-L667","documentation":"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.","triggerScenarios":"`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).","commonSituations":"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.","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"],"exampleFix":"// before\nconst Point = (x, y) => ({ x, y });\nconst p = new Point(1, 2); // not a constructor\n// after\nconst Point = (x, y) => ({ x, y });\nconst p = Point(1, 2);","handlingStrategy":"type-guard","validationCode":"if (typeof C === 'function' && !C.prototype || isArrow(C)) { /* call without new */ }","typeGuard":"function isConstructable(f) { try { return typeof f === 'function' && /^\\s*(class|function)/.test(String(f)); } catch (e) { return false; } }","tryCatchPattern":"try { var o = new C(); } catch (e) { if (String(e).includes('is not a constructor')) { o = C(); } else { throw e; } }","preventionTips":["Don't use new with arrow functions or methods","Prefer class syntax when construction is intended","Document which exported helpers are factories vs constructors"],"tags":["javascript","constructor","typeerror","new","arrow-function"],"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"}