karatelabs/karate · error · JsErrorException

AggregateError requires an iterable of errors

Error message

AggregateError requires an iterable of errors

What it means

AggregateError's first argument must be iterable (spec §20.5.7.1.1 step 3); its elements become the `errors` property. Passing null or undefined means there is nothing to iterate, so Karate throws this TypeError before iteration begins.

Solutions

  1. Pass an array (even empty): new AggregateError([], 'message').
  2. Default the argument: new AggregateError(errors ?? [], msg).
  3. Fix upstream code that produces null instead of an errors array.

Example fix

// before
throw new AggregateError(errors, 'all failed'); // TypeError when errors is null
// after
throw new AggregateError(errors ?? [], 'all failed');
Defensive patterns

Strategy: validation

Validate before calling

if (!Array.isArray(errors)) throw new Error('AggregateError needs an array of errors');

Type guard

function isIterable(v) { return v != null && typeof v[Symbol.iterator] === 'function'; }

Try / catch

try { throw new AggregateError(errors ?? [], 'aggregated'); } catch (e) { if (e instanceof TypeError && /iterable of errors/.test(e.message)) { /* fix args */ } throw e; }

Prevention

When it happens

Trigger: new AggregateError(), new AggregateError(null), new AggregateError(undefined), or a variable holding null passed as the errors argument (e.g. collected errors list that was never initialized).

Common situations: Promise.any-style aggregation code where the error list is conditionally built, refactoring that changed an empty array to null, unhandled Promise.any rejection handlers forwarding null.

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsErrorConstructor.java:97

     */
    private static String toMessageString(Object value, CoreContext cc) {
        if (value instanceof ObjectLike inner && cc != null) {
            value = Terms.toPrimitive(inner, "string", cc);
            if (cc.isError()) return null;
        }
        if (value == null) return "null";
        if (value == Terms.UNDEFINED) return "undefined";
        return value.toString();
    }

    /**
     * AggregateError(errors, message?, options?): iterate errors into an Array
     * own property, set message + cause as for plain Error. Spec §20.5.7.1.1.
     */
    private Object constructAggregate(Context context, Object[] args) {
        Object errorsArg = args.length > 0 ? args[0] : Terms.UNDEFINED;
        if (errorsArg == null || errorsArg == Terms.UNDEFINED) {
            throw JsErrorException.typeError("AggregateError requires an iterable of errors");
        }
        CoreContext cc = context instanceof CoreContext c ? c : null;
        List<Object> collected = new ArrayList<>();
        JsIterator iter = IterUtils.getIterator(errorsArg, context);
        while (iter.hasNext()) {
            collected.add(iter.next());
        }
        String message = null;
        if (args.length > 1 && args[1] != Terms.UNDEFINED) {
            message = toMessageString(args[1], cc);
            if (cc != null && cc.isError()) return Terms.UNDEFINED;
        }
        JsError instance = new JsError(errorPrototype);
        if (message != null) {
            instance.defineOwn("message", message, MESSAGE_ATTRS);
        }
        instance.captureStack(cc);
        installCauseFromOptions(instance, args, 2, cc);

View on GitHub (pinned to a22eb90246)