{"record":{"id":"28022f232162191c","repo":"karatelabs/karate","slug":"cannot-assign-to-read-only-property-length-of-object-object","errorCode":null,"errorMessage":"Cannot assign to read only property 'length' of object '[object Array]'","messagePattern":"Cannot assign to read only property 'length' of object '\\[object Array\\]'","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsArrayPrototype.java","lineNumber":224,"sourceCode":"     * method (pop/shift/push/unshift/sort/splice/reverse/fill/copyWithin).\n     * On a {@link JsArray} routes through {@link JsArray#handleLengthAssign}\n     * so {@link JsArray.ArrayLength#applySet} applies the truncate / extend\n     * (and HOLE-pad as needed); throws TypeError when length is non-writable\n     * per the spec's {@code Throw=true} contract. On a generic {@code ObjectLike}\n     * receiver (the {@code obj.shift = Array.prototype.shift; obj.shift()}\n     * pattern) writes via {@link PropertyAccess#setByName} so a setter\n     * installed at {@code length} on the proto chain fires.\n     * <p>\n     * Critically called <em>after</em> the spec's Get / Delete / Set\n     * per-element steps so prototype getter/setter side-effects observable\n     * via call-count assertions ({@code set-length-array-length-is-non-writable.js}\n     * cluster) match — a getter that flips length to non-writable still has\n     * fired exactly once before the throw.\n     */\n    private static void setLength(ObjectLike target, int newLen, CoreContext ctx) {\n        if (target instanceof JsArray arr) {\n            if (!arr.handleLengthAssign(newLen, ctx)) {\n                throw JsErrorException.typeError(LENGTH_NON_WRITABLE);\n            }\n            return;\n        }\n        PropertyAccess.setByName(target, \"length\", newLen, ctx, null);\n    }\n\n    /**\n     * Spec-shape {@code Get(O, name)} — proto-walking via the receiver-aware\n     * {@link ObjectLike#getMember(String, Object, CoreContext)} so accessor\n     * descriptors installed anywhere in the chain dispatch with the right\n     * {@code this}. Returns {@link Terms#UNDEFINED} when the chain bottoms\n     * out so callers don't have to null-coalesce.\n     */\n    private static Object specGet(ObjectLike target, String name, CoreContext ctx) {\n        Object v = target.getMember(name, target, ctx);\n        return v == null ? Terms.UNDEFINED : v;\n    }\n","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsArrayPrototype.java#L206-L242","documentation":"When array code (push, pop, shift, unshift, splice) must update `length`, and length has been made non-writable (e.g. the array was frozen/sealed or its length property descriptor set writable:false), Karate throws this TypeError instead of silently failing. The setLength helper routes through handleLengthAssign and throws LENGTH_NON_WRITABLE when the assignment is refused.","triggerScenarios":"Calling arr.push(x)/pop()/shift()/unshift()/splice() on an array whose 'length' property is non-writable (Object.freeze(arr) or Object.defineProperty(arr,'length',{writable:false})).","commonSituations":"Freezing arrays for immutability then still trying to mutate them via push/splice; sharing a frozen config array and accidentally mutating it; libraries that defensively freeze exported arrays.","solutions":["Remove the freeze/non-writable descriptor, or work on a copy: arr.slice() before mutating","Use non-mutating alternatives (concat, slice, spread) that return new arrays","If the array must stay frozen, restructure code to replace rather than mutate"],"exampleFix":"// before\nvar frozen = Object.freeze([1,2,3]); frozen.push(4); // TypeError\n// after\nvar updated = frozen.concat(4);","handlingStrategy":"try-catch","validationCode":"function isMutable(arr) { try { var d = Object.getOwnPropertyDescriptor(arr, 'length'); return d ? d.writable !== false : true; } catch (e) { return false; } }","typeGuard":"function isFrozenArr(arr) { try { return Object.isFrozen(arr) || Object.getOwnPropertyDescriptor(arr, 'length').writable === false; } catch (e) { return false; } }","tryCatchPattern":"try { arr.push(x); } catch (e) { if (String(e).indexOf(\"read only property 'length'\") !== -1) { arr = arr.concat(x); } else { throw e; } }","preventionTips":["Don't call mutating methods (push/pop/shift/unshift/splice) on frozen arrays","Prefer non-mutating operations (concat, slice, spread) for frozen/shared data","Check Object.isFrozen before mutating arrays received from other modules"],"tags":["javascript","array","type-error","immutability"],"backgroundTag":"unsupported-operation","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"}