karatelabs/karate · error · TypeError

Constructor WeakMap requires 'new'

Error message

Constructor WeakMap requires 'new'

What it means

WeakMap is a constructor, not a plain callable function. Per the ECMAScript spec (and V8 behavior), calling WeakMap() without new throws 'Constructor WeakMap requires new'. Karate's JsWeakMapConstructor.call checks CallInfo.constructor and throws this TypeError when the flag is absent.

Solutions

  1. Always instantiate with new: const wm = new WeakMap().
  2. If the constructor may be called either way, wrap it: function safeWeakMap(){ return new WeakMap(); }.
  3. Search scripts for `WeakMap(` occurrences and add the missing `new` keyword.
  4. Use new.target-aware wrappers if you must support both styles in shared code.

Example fix

// before
const wm = WeakMap();

// after
const wm = new WeakMap();
Defensive patterns

Strategy: validation

Try / catch

try { var wm = WeakMap(); } catch (e) { if (String(e).indexOf('requires') !== -1) wm = new WeakMap(); }

Prevention

When it happens

Trigger: Evaluating `const wm = WeakMap()` (no new) in Karate JS; dynamic invocation like `const M = WeakMap; M()`; destructured or re-assigned constructor references losing new-call syntax.

Common situations: Porting code written for APIs that allowed both call styles; refactoring that dropped `new`; template-generated code where the new keyword was lost; confusion after using classes where calling without new is impossible.

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


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/ec82336d3f8f9193. Report an issue: GitHub.

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsWeakMapConstructor.java:46

/**
 * Global {@code WeakMap} constructor — mirrors {@link JsMapConstructor}: no
 * {@code new} is a TypeError, and construction from an iterable of
 * {@code [key, value]} pairs invokes {@code this.set(k, v)} through the
 * prototype chain so a user-overridden {@code WeakMap.prototype.set} is honored.
 */
class JsWeakMapConstructor extends JsFunction {

    JsWeakMapConstructor() {
        this.name = "WeakMap";
        defineOwn("prototype", JsWeakMapPrototype.INSTANCE, PropertySlot.INTRINSIC);
    }

    @Override
    public Object call(Context context, Object[] args) {
        CallInfo callInfo = context.getCallInfo();
        boolean isNew = callInfo != null && callInfo.constructor;
        if (!isNew) {
            throw JsErrorException.typeError("Constructor WeakMap requires 'new'");
        }
        JsWeakMap map = new JsWeakMap();
        if (args.length == 0 || args[0] == null || args[0] == Terms.UNDEFINED) {
            return map;
        }
        Object setFn = map.getMember("set");
        if (!(setFn instanceof JsCallable adder)) {
            throw JsErrorException.typeError("WeakMap.prototype.set is not callable");
        }
        JsIterator iter = IterUtils.getIterator(args[0], context);
        CoreContext cc = context instanceof CoreContext c ? c : null;
        Object savedThis = cc != null ? cc.thisObject : null;
        try {
            while (iter.hasNext()) {
                Object entry = iter.next();
                if (!(entry instanceof List) && !(entry instanceof ObjectLike)) {
                    throw JsErrorException.typeError("Iterator value " + entry + " is not an entry object");
                }

View on GitHub (pinned to a22eb90246)