karatelabs/karate · error · JsErrorException
Cannot define property , object is not extensible
Error message
Cannot define property , object is not extensible
What it means
Object.defineProperty() on a non-extensible ObjectLike target throws this TypeError when the property does not already exist. Once Object.preventExtensions()/freeze()/seal() has been applied, adding brand-new keys is forbidden by spec; existing keys can still be redefined (subject to their attributes). ObjectLikes that do not model extensibility state default to perpetually-extensible and pass through.
Solutions
- Remove the preventExtensions/seal/freeze call on the object, or apply it only after all properties are added
- Use Object.defineProperty on an existing property instead of adding a new one (redefinition of existing keys is allowed on sealed objects)
- Check Object.isExtensible(obj) before defining and skip or clone the object if frozen: define on a shallow copy instead
- If the freeze came from a library, configure it to not freeze, or work on your own copy
Example fix
// before
const cfg = Object.freeze({ host: 'x' });
Object.defineProperty(cfg, 'port', { value: 8080 }); // TypeError
// after
const cfg = Object.freeze({ host: 'x' });
const cfg2 = { ...cfg, port: 8080 }; // extend via copy instead Defensive patterns
Strategy: validation
Validate before calling
if (!Object.isExtensible(obj)) throw new Error('target is not extensible; cannot add ' + key); Type guard
function canDefineNew(obj, key) { return obj != null && Object.isExtensible(obj) && !(key in obj); } Try / catch
try { Object.defineProperty(obj, key, desc); } catch (e) { if (String(e.message).includes('not extensible')) obj = { ...obj, [key]: desc.value }; else throw e; } Prevention
- Track freeze/seal calls centrally so late extensions are visible in review
- Prefer building the full object literal, then freeze once at the end
- Use Object.isExtensible assertions in tests for shared/config objects
When it happens
Trigger: Calling Object.defineProperty(obj, 'newKey', {...}) where obj was made non-extensible via preventExtensions/seal/freeze and 'newKey' is not an own property. Also thrown for symbol keys through the parallel check at the JsObject branch.
Common situations: Freezing a config object for immutability then later trying to attach a cache field; sealing a shared module namespace; a library freezing an object the consumer then extends.
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
- NoSuchElementException
- Cannot assign to read only property 'length' of object…
- Cannot redefine property:
- Object.defineProperty called on non-object
- property key is null
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/36a60b94d2a4532a.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsObjectConstructor.java:614
// fires when the new descriptor is itself a data descriptor; for a
// generic descriptor, only the attribute byte changes.
boolean isGeneric = !isAccessor && !isData;
if (isAccessor && isData) {
throw JsErrorException.typeError(
"Invalid property descriptor. Cannot both specify accessors and a value or writable attribute");
}
Object target = args[0];
// Detected before the string-keyed checks below: `prop` is a symbol's
// descriptive string, which is not a key of the string store, so those
// checks would read the wrong slot (and reject on a frozen object).
JsSymbol symKey = JsSymbol.keyedBy(args[1]);
boolean keyExists = symKey == null && ownKeys(target).contains(prop);
// Extensibility check — ObjectLikes that don't model state inherit
// the perpetually-extensible default and pass through.
if (symKey == null && !keyExists && target instanceof ObjectLike ol && !ol.isExtensible()) {
throw JsErrorException.typeError("Cannot define property " + prop + ", object is not extensible");
}
// Validate accessor shapes early so we can fall through to the unified write below.
// Spec ToPropertyDescriptor §6.2.5.5: if Get/Set is present but not
// {@code undefined} AND not callable, throw TypeError. {@code null}
// is a non-callable non-undefined value — must throw (test262
// {@code defineProperty/15.2.3.6-3-{8,13}}). Only literal undefined
// is the spec-permitted "absent" sentinel.
JsCallable newGetter = null;
JsCallable newSetter = null;
if (isAccessor) {
if (hasGet) {
Object g = descRead(descObj, descMap, "get", cc);
if (g != Terms.UNDEFINED) {
if (!(g instanceof JsCallable c)) {
throw JsErrorException.typeError("Getter must be a function");
}
newGetter = c;View on GitHub (pinned to a22eb90246)