{"record":{"id":"d2eaed45008c28bb","repo":"karatelabs/karate","slug":"cannot-read-properties-of-object-reading-i","errorCode":null,"errorMessage":"cannot read properties of ${object} (reading '[${i}]')","messagePattern":"cannot read properties of (.+?) \\(reading '\\[(.+?)\\]'\\)","errorType":"exception","errorClass":"JsErrorException (typeError)","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/PropertyAccess.java","lineNumber":884,"sourceCode":"        context.callReceiver = object;\n        return result;\n    }\n\n    private static Object getByIndex(Object object, Object index, boolean optional,\n                                      CoreContext context, boolean functionCall) {\n        JsSymbol sym = JsSymbol.keyedBy(index);\n        if (sym != null) {\n            // a minted symbol addresses the symbol store, never a string key\n            return object instanceof JsObject jo ? jo.getSymbolMember(sym, object, context) : Terms.UNDEFINED;\n        }\n        if (!functionCall && index instanceof Number n) {\n            int i = denseIndex(n);\n            if (i < 0) {\n                return getByName(object, Terms.toPropertyKey(index), optional, context, functionCall);\n            }\n            if (object == null || object == Terms.UNDEFINED) {\n                if (optional) return Terms.UNDEFINED;\n                throw JsErrorException.typeError(\"cannot read properties of \" + object + \" (reading '[\" + i + \"]')\");\n            }\n            if (object instanceof JsArray array) {\n                return array.getIndexedValue(i, array, context);\n            }\n            if (object instanceof List<?> list) {\n                if (i < 0 || i >= list.size()) return Terms.UNDEFINED;\n                // Translate JsArray.HOLE → undefined so callers reading from\n                // a raw List that was sourced from a sparse JsArray (e.g.\n                // Array.prototype.* methods that return rawList directly)\n                // never see the sentinel.\n                return JsArray.unwrapHole(list.get(i));\n            }\n            if (object instanceof String s) {\n                if (i < 0 || i >= s.length()) return Terms.UNDEFINED;\n                return s.substring(i, i + 1);\n            }\n            if (object instanceof byte[] bytes) {\n                if (i < 0 || i >= bytes.length) return Terms.UNDEFINED;","sourceCodeStart":866,"sourceCodeEnd":902,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/PropertyAccess.java#L866-L902","documentation":"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.","triggerScenarios":"`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).","commonSituations":"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.","solutions":["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.","Use optional access `a.b?[0]` / `?.` syntax so a null base degrades to undefined instead of throwing.","Fix the upstream data: ensure the API/call actually returns the expected array before indexing it.","Provide a default: `* def items = response.items || []` before indexing."],"exampleFix":"// before\n* match response.items[0].name == 'x'\n// after\n* def items = response.items || []\n* match items[0].name == 'x'","handlingStrategy":"type-guard","validationCode":"* def safe = response.items ? response.items : []\n* assert karate.sizeOf(safe) > 0","typeGuard":"function isArrayLike(v) { return v != null && (Array.isArray(v) || karate.sizeOf(v) > 0); }","tryCatchPattern":null,"preventionTips":["Default missing arrays to [] before indexing.","Match payloads against a schema (#array / ##[] ) before element access.","Prefer fuzzy matchers (#present, #notpresent) over raw element reads for optional fields.","Use optional chaining a?.b[0] for potentially null bases."],"tags":["javascript","type-error","null-pointer","array-index"],"backgroundTag":"type-mismatch","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}