karatelabs/karate · error · JsErrorException

Error.prototype.toString called on non-object

Error message

Error.prototype.toString called on non-object

What it means

Error.prototype.toString builds the 'Name: message' string from the receiver's `name` and `message` properties, which requires `this` to be an object (spec §20.5.4.2 step 1). Calling it with a primitive receiver throws this TypeError in Karate, which does not auto-box primitives here.

Solutions

  1. Call toString as a method on an Error object: err.toString().
  2. Use Function.prototype.call with an object: Error.prototype.toString.call(err).
  3. Stringify primitives directly (String(value)) instead of routing through Error.prototype.toString.

Example fix

// before
const label = Error.prototype.toString.call('bad input'); // TypeError
// after
const label = typeof v === 'object' && v ? String(v) : String(v);
Defensive patterns

Strategy: type-guard

Validate before calling

if (v === null || typeof v !== 'object') throw new Error('Error.prototype.toString needs an object');

Type guard

function isErrorLike(v) { return v !== null && typeof v === 'object'; }

Try / catch

try { return Error.prototype.toString.call(v); } catch (e) { if (e instanceof TypeError) return String(v); throw e; }

Prevention

When it happens

Trigger: Error.prototype.toString.call('boom'), .call(42), .call(undefined), or storing the method reference and calling it unbound (`const t = Error.prototype.toString; t()`).

Common situations: Generic stringifier utilities that borrow Error.prototype.toString for any value, template rendering of error entries where the entry is a raw string, refactors that lost the bound `this`.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsErrorPrototype.java:75

            install("toString", 0, JsErrorPrototype::toStringMethod);
        }
    }

    String getTypeName() {
        return typeName;
    }

    /**
     * Spec §20.5.3.4 Error.prototype.toString. Reads {@code name} / {@code message}
     * via the receiver (proto chain), defaulting to "Error" / "" when undefined.
     * Both values run through {@code Terms.toStringCoerce} so a custom
     * {@code valueOf}/{@code toString} that throws (e.g. via {@code @@toPrimitive})
     * propagates the abrupt completion to the caller.
     */
    private static Object toStringMethod(Context context, Object[] args) {
        Object thisObj = context.getThisObject();
        if (!(thisObj instanceof ObjectLike obj)) {
            throw JsErrorException.typeError("Error.prototype.toString called on non-object");
        }
        CoreContext cc = context instanceof CoreContext c ? c : null;
        String name = readToString(obj, "name", "Error", cc);
        if (name == null) return Terms.UNDEFINED;
        String msg = readToString(obj, "message", "", cc);
        if (msg == null) return Terms.UNDEFINED;
        if (name.isEmpty()) return msg;
        if (msg.isEmpty()) return name;
        return name + ": " + msg;
    }

    /**
     * Spec ToString (§7.1.17) on an own/prototype-chain field, with a default
     * applied when the value is {@code undefined}. ObjectLike values dispatch
     * through {@link Terms#toPrimitive} (hint string) so a custom
     * {@code @@toPrimitive} / {@code toString} / {@code valueOf} that throws
     * propagates via {@code context.isError()}; we surface the abrupt
     * completion to the caller as {@code null}.

View on GitHub (pinned to a22eb90246)