karatelabs/karate · error · JsErrorException (typeError)

called on null or undefined

Error message

${methodName} called on null or undefined

What it means

Methods like String.prototype helpers require the `this` value to be object-coercible. Terms.requireObjectCoercible throws a TypeError naming the method when it is invoked on null or undefined, producing a message that reads like a JS engine's instead of a generic NPE.

Solutions

  1. Add a null/undefined fallback before the method call: (v ?? '').trim()
  2. Short-circuit: if (v != null) v.trim();
  3. Use optional chaining where supported: v?.trim()

Example fix

// before
var t = response.token.trim();
// after
var t = (response.token ?? '').trim();
Defensive patterns

Strategy: type-guard

Validate before calling

if (v === null || v === undefined) throw new Error('value required before calling ' + methodName);

Type guard

function isObjectCoercible(v) { return v !== null && v !== undefined; }

Try / catch

try { t = v.trim(); } catch (e) { if (String(e).includes('called on null or undefined')) t = ''; else throw e; }

Prevention

When it happens

Trigger: Calling e.g. `null.toString()`, `undefined.trim()`, or a String.prototype method with `this` = null/undefined inside karate-js expressions or script functions.

Common situations: Chained calls on values that can be null/undefined, e.g. `(response.headers['x'] || '').trim()` written without the fallback, or map lookups returning undefined then having a method called on them.

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/Terms.java:1506

        int eIdx = s.indexOf('E');
        if (eIdx < 0) return s;
        String mantissa = s.substring(0, eIdx);
        String exp = s.substring(eIdx + 1);
        if (mantissa.endsWith(".0")) mantissa = mantissa.substring(0, mantissa.length() - 2);
        if (exp.charAt(0) != '+' && exp.charAt(0) != '-') exp = "+" + exp;
        return mantissa + "e" + exp;
    }

    /**
     * Spec {@code RequireObjectCoercible} (§7.2.1) — gate at the top of every
     * built-in whose receiver feeds {@code ToObject} / {@code ToString} (e.g.
     * {@code String.prototype.*}). null / undefined throw TypeError; everything
     * else passes through. {@code methodName} is woven into the message so the
     * thrown error reads like a JS engine's, not a generic NPE.
     */
    public static void requireObjectCoercible(Object value, String methodName) {
        if (value == null || value == UNDEFINED) {
            throw JsErrorException.typeError(methodName + " called on null or undefined");
        }
    }

    public static String toStringCoerce(Object o, CoreContext context) {
        if (o instanceof String s) {
            return s;
        }
        // §7.1.17 ToString throws for a symbol. String(sym) is the one operation
        // that does not (JsString.getObject special-cases it), and ToPropertyKey
        // has its own branch above, so both stay reachable.
        if (o instanceof JsSymbol) {
            throw JsErrorException.typeError("Cannot convert a Symbol value to a string");
        }
        if (o instanceof Number n) {
            return numberToString(n);
        }
        if (o == null) {
            return "null";

View on GitHub (pinned to a22eb90246)