karatelabs/karate · error · JsErrorException (typeError)

cannot read properties of

Error message

cannot read properties of ${object} (reading '[${i}]')

What it means

A TypeError from Karate's indexed property access: the engine evaluated `expr[i]` where the base expression was null or undefined, so element i cannot be read. The engine first tries to parse the index as a dense integer; only when it is a valid non-negative index and the object is null/undefined does it throw. Optional chaining (`?.[`) bypasses this and returns undefined instead.

Solutions

  1. Guard the base value before indexing: check it is non-null (or use `karate.sizeOf()`/`karate.match`) or restructure the match to use `#present`/`#notpresent` markers.
  2. Use optional access `a.b?[0]` / `?.` syntax so a null base degrades to undefined instead of throwing.
  3. Fix the upstream data: ensure the API/call actually returns the expected array before indexing it.
  4. Provide a default: `* def items = response.items || []` before indexing.

Example fix

// before
* match response.items[0].name == 'x'
// after
* def items = response.items || []
* match items[0].name == 'x'
Defensive patterns

Strategy: type-guard

Validate before calling

* def safe = response.items ? response.items : []
* assert karate.sizeOf(safe) > 0

Type guard

function isArrayLike(v) { return v != null && (Array.isArray(v) || karate.sizeOf(v) > 0); }

Prevention

When it happens

Trigger: `null[0]`, `undefined[0]`, or chained access like `a.b[0]` where `a.b` is null/undefined; e.g. `match response.items[0] == ...` when the response has no `items`. Not thrown for Map/List bases (out-of-range List index just returns undefined).

Common situations: Reading array elements from an API response where an expected field is missing or null, empty-body responses, karate config JSON where a nested node is absent, match expressions written for a happy-path payload hitting an error payload.

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/d2eaed45008c28bb. Report an issue: GitHub.

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/PropertyAccess.java:884

        context.callReceiver = object;
        return result;
    }

    private static Object getByIndex(Object object, Object index, boolean optional,
                                      CoreContext context, boolean functionCall) {
        JsSymbol sym = JsSymbol.keyedBy(index);
        if (sym != null) {
            // a minted symbol addresses the symbol store, never a string key
            return object instanceof JsObject jo ? jo.getSymbolMember(sym, object, context) : Terms.UNDEFINED;
        }
        if (!functionCall && index instanceof Number n) {
            int i = denseIndex(n);
            if (i < 0) {
                return getByName(object, Terms.toPropertyKey(index), optional, context, functionCall);
            }
            if (object == null || object == Terms.UNDEFINED) {
                if (optional) return Terms.UNDEFINED;
                throw JsErrorException.typeError("cannot read properties of " + object + " (reading '[" + i + "]')");
            }
            if (object instanceof JsArray array) {
                return array.getIndexedValue(i, array, context);
            }
            if (object instanceof List<?> list) {
                if (i < 0 || i >= list.size()) return Terms.UNDEFINED;
                // Translate JsArray.HOLE → undefined so callers reading from
                // a raw List that was sourced from a sparse JsArray (e.g.
                // Array.prototype.* methods that return rawList directly)
                // never see the sentinel.
                return JsArray.unwrapHole(list.get(i));
            }
            if (object instanceof String s) {
                if (i < 0 || i >= s.length()) return Terms.UNDEFINED;
                return s.substring(i, i + 1);
            }
            if (object instanceof byte[] bytes) {
                if (i < 0 || i >= bytes.length) return Terms.UNDEFINED;

View on GitHub (pinned to a22eb90246)