karatelabs/karate · error · JsErrorException
Cannot redefine property: length
Error message
Cannot redefine property: length
What it means
Redefining the 'length' property of a JsArray via Object.defineProperty throws this TypeError when a non-configurable array index within the truncation range blocks the resize. Per spec, setting a smaller length must delete trailing elements; if any blocked element cannot be deleted, length is left partially truncated and a TypeError is raised.
Solutions
- Do not freeze/seal arrays you intend to truncate; keep elements configurable
- Truncate via slice/copy into a new array instead of redefining length
- Remove or make configurable any non-configurable index below the target length first
- Use arr.length = n assignment only on arrays with all-configurable elements
Example fix
// before
const arr = [1,2,3];
Object.defineProperty(arr, 1, { value: 2, configurable: false });
Object.defineProperty(arr, 'length', { value: 1 }); // TypeError
// after
const arr = [1,2,3];
const short = arr.slice(0, 1); // new array, original untouched Defensive patterns
Strategy: try-catch
Validate before calling
const blocked = arr.some((v, i) => i < newLen && !Object.getOwnPropertyDescriptor(arr, i)?.configurable);
Type guard
function canTruncate(arr, newLen) { return arr.every((v, i) => i >= newLen || (Object.getOwnPropertyDescriptor(arr, i) || {}).configurable !== false); } Try / catch
try { Object.defineProperty(arr, 'length', { value: newLen }); } catch (e) { if (String(e.message).includes('length')) arr = arr.slice(0, newLen); else throw e; } Prevention
- Do not freeze/seal arrays that need resizing; use readonly copies instead
- Prefer slice/splice/push over redefining length
- Keep array elements configurable when using Object.defineProperty on length
When it happens
Trigger: Object.defineProperty(arr, 'length', { value: smaller }) (or writable changes) on an array where an index < newLength is non-configurable, e.g. Object.defineProperty(arr, 0, {value:1, configurable:false}) beforehand, or on a frozen array.
Common situations: Freezing arrays then trying to shrink length; sealing arrays with Object.seal (which makes all elements non-configurable) then truncating.
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
- array index too large for dense storage:
- Array.prototype.* called on null or undefined
- callback is not a function
- Cannot assign to read only property 'length' of object…
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/aac390c717ae59bf.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsObjectConstructor.java:767
if (isAccessor) {
// Merge with existing accessor: defining only `get` keeps the existing setter,
// and vice versa. Matches the literal path's merge behavior in evalLitObject.
JsCallable getter = newGetter;
JsCallable setter = newSetter;
if (existingIsAccessor) {
if (!hasGet) getter = existingAcc.getter;
if (!hasSet) setter = existingAcc.setter;
}
applyDefineAccessor(target, prop, getter, setter, newAttrs);
} else if (isArrayLength) {
// Skip the generic applyDefine path — defineLength bypasses the
// re-coercion that handleLengthAssign would run, since coercedLength
// already encodes the spec-validated Uint32.
boolean ok = ((JsArray) target).defineLength(coercedLength.intValue(), newAttrs);
if (!ok) {
// Non-configurable index in truncate range blocked the rest;
// partial-truncate already applied — report TypeError per spec.
throw JsErrorException.typeError("Cannot redefine property: length");
}
} else if (isGeneric && existingIsAccessor) {
// Generic descriptor on existing accessor: spec preserves the
// accessor descriptor and only updates the attribute byte. Going
// through applyDefine here would clobber the AccessorSlot with a
// fresh DataSlot carrying undefined (test262
// {@code defineProperty/15.2.3.6-4-{59,82-7..24,272}}).
applyAttrsOnly(target, prop, newAttrs);
} else if (hasValue) {
applyDefine(target, prop, descRead(descObj, descMap, "value", cc), newAttrs);
} else if (!keyExists) {
// New key created via attribute-only descriptor: spec says value defaults
// to undefined.
applyDefine(target, prop, Terms.UNDEFINED, newAttrs);
} else if (existingIsAccessor) {
// Data descriptor (writable-only, no value) replacing an accessor:
// spec switches shape; value defaults to undefined.
applyDefine(target, prop, Terms.UNDEFINED, newAttrs);View on GitHub (pinned to a22eb90246)