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

  1. Remove the freeze/non-writable descriptor, or work on a copy: arr.slice() before mutating
  2. Use non-mutating alternatives (concat, slice, spread) that return new arrays
  3. 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

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


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)