karatelabs/karate · error · JsErrorException (typeError)

get by index [ ] for non-array

Error message

get by index [${i}] for non-array: ${object}

What it means

Thrown by Karate's `get by index` path when an index-style access is applied to a value that is neither a JsArray/List nor a Map/ObjectLike — e.g. a string, number, or boolean. Arrays and maps support `[i]` lookups; anything else has no indexed value, so the engine raises a TypeError naming the offending value.

Solutions

  1. Verify the actual type of the value (print it or match it against `#array`/`#object`/`#string`) before indexing.
  2. Fix the JSON path or expression so it selects the collection, not a leaf.
  3. Convert/unwrap the value first if it is a single object that should be a one-element list (e.g. `* def list = karate.sizeOf(x) != null ? x : [x]`).
  4. Use schema matching (`match each`, `##[] array`) to catch shape drift early.

Example fix

// before (name is a string)
* match response.name[0] == 'x'
// after
* match response.name == 'x'
// or if it can be either:
* match response.name == '#(karate.sizeOf(response.name) != null ? response.name[0] : response.name)'
Defensive patterns

Strategy: validation

Validate before calling

* match response.field == '#array' // or '#object' / '#string' before indexing

Type guard

function canIndex(v) { return v instanceof Array || (v && typeof v === 'object'); }

Prevention

When it happens

Trigger: Expressions like `response[0]` where `response` is a scalar/string, or `get by index` on a non-collection JSON value; also `karate.get('x[0]')` style access where `x` resolved to a primitive.

Common situations: Assuming an API field is an array when it is a string or object, indexing a JSON path result that pointed at a leaf value, schema drift between expected and actual payload shapes (array vs single object).

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

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

                // 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;
                return bytes[i] & 0xFF;
            }
            ObjectLike converted = Terms.toObjectLike(object);
            if (converted instanceof JsArray jsArray) {
                return jsArray.getIndexedValue(i, jsArray, context);
            }
            if (object instanceof Map || object instanceof ObjectLike) {
                return getByName(object, Terms.toPropertyKey(index), optional, context, functionCall);
            }
            throw JsErrorException.typeError("get by index [" + i + "] for non-array: " + object);
        }
        return getByName(object, Terms.toPropertyKey(index), optional, context, functionCall);
    }

    private static Object getByName(Object object, String name, boolean optional,
                                     CoreContext context, boolean functionCall) {
        return getByName(object, name, optional, context, functionCall, object);
    }

    /** Receiver-aware variant for super references (§13.3.7.3): the lookup
     *  walks {@code object}'s chain, but any getter runs with {@code receiver}
     *  as its {@code this}. All non-super callers pass {@code object} itself
     *  via the delegating overload above. */
    private static Object getByName(Object object, String name, boolean optional,
                                     CoreContext context, boolean functionCall, Object receiver) {
        if (object == null || object == Terms.UNDEFINED) {
            // Reading a property of null/undefined is a TypeError (or undefined under ?.).
            // Do NOT fall back to a same-named scope variable: `a.b.c` where `a.b` is null

View on GitHub (pinned to a22eb90246)