karatelabs/karate · error · JsErrorException
Cannot assign to read only property 'length' of object…
Error message
Cannot assign to read only property 'length' of object '[object Array]'
What it means
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.
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
Example fix
// before var frozen = Object.freeze([1,2,3]); frozen.push(4); // TypeError // after var updated = frozen.concat(4);
Defensive patterns
Strategy: try-catch
Validate before calling
function isMutable(arr) { try { var d = Object.getOwnPropertyDescriptor(arr, 'length'); return d ? d.writable !== false : true; } catch (e) { return false; } } Type guard
function isFrozenArr(arr) { try { return Object.isFrozen(arr) || Object.getOwnPropertyDescriptor(arr, 'length').writable === false; } catch (e) { return false; } } Try / catch
try { arr.push(x); } catch (e) { if (String(e).indexOf("read only property 'length'") !== -1) { arr = arr.concat(x); } else { throw e; } } Prevention
- 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
When it happens
Trigger: 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})).
Common situations: 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.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Array.from requires an iterable or array-like object, not
- is not iterable
- Array.prototype.* called on null or undefined
- callback is not a function
- Reduce of empty array with no initial value
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/28022f232162191c.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsArrayPrototype.java:224
* method (pop/shift/push/unshift/sort/splice/reverse/fill/copyWithin).
* On a {@link JsArray} routes through {@link JsArray#handleLengthAssign}
* so {@link JsArray.ArrayLength#applySet} applies the truncate / extend
* (and HOLE-pad as needed); throws TypeError when length is non-writable
* per the spec's {@code Throw=true} contract. On a generic {@code ObjectLike}
* receiver (the {@code obj.shift = Array.prototype.shift; obj.shift()}
* pattern) writes via {@link PropertyAccess#setByName} so a setter
* installed at {@code length} on the proto chain fires.
* <p>
* Critically called <em>after</em> the spec's Get / Delete / Set
* per-element steps so prototype getter/setter side-effects observable
* via call-count assertions ({@code set-length-array-length-is-non-writable.js}
* cluster) match — a getter that flips length to non-writable still has
* fired exactly once before the throw.
*/
private static void setLength(ObjectLike target, int newLen, CoreContext ctx) {
if (target instanceof JsArray arr) {
if (!arr.handleLengthAssign(newLen, ctx)) {
throw JsErrorException.typeError(LENGTH_NON_WRITABLE);
}
return;
}
PropertyAccess.setByName(target, "length", newLen, ctx, null);
}
/**
* Spec-shape {@code Get(O, name)} — proto-walking via the receiver-aware
* {@link ObjectLike#getMember(String, Object, CoreContext)} so accessor
* descriptors installed anywhere in the chain dispatch with the right
* {@code this}. Returns {@link Terms#UNDEFINED} when the chain bottoms
* out so callers don't have to null-coalesce.
*/
private static Object specGet(ObjectLike target, String name, CoreContext ctx) {
Object v = target.getMember(name, target, ctx);
return v == null ? Terms.UNDEFINED : v;
}
View on GitHub (pinned to a22eb90246)