karatelabs/karate · error · JsErrorException

Array.prototype.* called on null or undefined

Error message

Array.prototype.* called on null or undefined

What it means

Every Array.prototype.* method performs spec ToObject on its this value, which rejects null and undefined outright. Karate's toReceiver throws this TypeError when the receiver is null or Terms.UNDEFINED, independent of strict mode.

Solutions

  1. Call the method on a real array or bound object: arr.map(fn)
  2. Bind a receiver: Array.prototype.map.call(arr, fn)
  3. Guard the receiver before the call: if (x == null) ...
  4. Initialize the variable to [] instead of null/undefined

Example fix

// before
const map = arr.map;
map(fn); // this === undefined
// after
arr.map(fn);
// or
const map = arr.map.bind(arr);
map(fn);
Defensive patterns

Strategy: type-guard

Validate before calling

if (receiver == null) throw new Error('receiver required for Array.prototype call');

Type guard

function isArrayReceiver(o) { return o != null && (Array.isArray(o) || typeof o === 'object'); }

Try / catch

try { return Array.prototype.map.call(recv, fn); } catch (e) { if (String(e.message).includes('null or undefined')) return []; throw e; }

Prevention

When it happens

Trigger: Calling any Array.prototype method (e.g. via target/receiver helpers) with this set to null or undefined — e.g. Array.prototype.map.call(null, fn), or a function invoked unbound where this is undefined in strict mode.

Common situations: Detached method references like `const m = arr.map; m(fn)`; sloppy-to-strict ported code; variables that are null because a lookup returned nothing.

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsArrayPrototype.java:454

                : Terms.objectToNumber(lenObj);
        if (ctx != null && ctx.isError()) return;
        double d = n == null ? Double.NaN : n.doubleValue();
        if (d + addCount > 9007199254740991.0) { // 2^53 - 1
            throw JsErrorException.typeError("Invalid array length");
        }
    }

    /** Spec-shape {@code O = ? ToObject(this value)}. Returns the receiver
     *  unchanged when it's already an {@link ObjectLike}; wraps raw Java
     *  Lists / arrays via {@link Terms#toObjectLike} (so a Java
     *  {@link java.util.ArrayList} surfaces as a {@link JsArray} sharing the
     *  underlying list — mutations propagate). Throws TypeError for
     *  {@code null} / {@code undefined} per spec — independent of strict
     *  mode (the spec ToObject step in every Array.prototype.* method
     *  rejects {@code null} / {@code undefined} directly). */
    private static ObjectLike toReceiver(Object thisObj) {
        if (thisObj == null || thisObj == Terms.UNDEFINED) {
            throw JsErrorException.typeError("Array.prototype.* called on null or undefined");
        }
        ObjectLike o = thisObj instanceof ObjectLike ol ? ol : Terms.toObjectLike(thisObj);
        if (o == null) {
            throw JsErrorException.typeError("Array.prototype.* called on null or undefined");
        }
        return o;
    }

    private static final Object[] EMPTY_ARGS = new Object[0];

    /** Spec {@code IsCallable} guard — every {@code Array.prototype.*}
     *  iteration method begins with a TypeError when the supplied callbackfn
     *  is not a function (spec FindViaPredicate / map / filter / forEach /
     *  every / some / reduce / reduceRight / flatMap step 1). The method
     *  name flows into the error so test262's
     *  {@code Array.prototype.map called on non-callable} style assertions
     *  carry the spec context. */
    private static JsCallable requireCallable(Object[] args, String methodName) {

View on GitHub (pinned to a22eb90246)