{"record":{"id":"36a60b94d2a4532a","repo":"karatelabs/karate","slug":"cannot-define-property-object-is-not-extensible","errorCode":null,"errorMessage":"Cannot define property , object is not extensible","messagePattern":"Cannot define property , object is not extensible","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsObjectConstructor.java","lineNumber":614,"sourceCode":"        // fires when the new descriptor is itself a data descriptor; for a\n        // generic descriptor, only the attribute byte changes.\n        boolean isGeneric = !isAccessor && !isData;\n        if (isAccessor && isData) {\n            throw JsErrorException.typeError(\n                    \"Invalid property descriptor. Cannot both specify accessors and a value or writable attribute\");\n        }\n\n        Object target = args[0];\n        // Detected before the string-keyed checks below: `prop` is a symbol's\n        // descriptive string, which is not a key of the string store, so those\n        // checks would read the wrong slot (and reject on a frozen object).\n        JsSymbol symKey = JsSymbol.keyedBy(args[1]);\n        boolean keyExists = symKey == null && ownKeys(target).contains(prop);\n\n        // Extensibility check — ObjectLikes that don't model state inherit\n        // the perpetually-extensible default and pass through.\n        if (symKey == null && !keyExists && target instanceof ObjectLike ol && !ol.isExtensible()) {\n            throw JsErrorException.typeError(\"Cannot define property \" + prop + \", object is not extensible\");\n        }\n\n        // Validate accessor shapes early so we can fall through to the unified write below.\n        // Spec ToPropertyDescriptor §6.2.5.5: if Get/Set is present but not\n        // {@code undefined} AND not callable, throw TypeError. {@code null}\n        // is a non-callable non-undefined value — must throw (test262\n        // {@code defineProperty/15.2.3.6-3-{8,13}}). Only literal undefined\n        // is the spec-permitted \"absent\" sentinel.\n        JsCallable newGetter = null;\n        JsCallable newSetter = null;\n        if (isAccessor) {\n            if (hasGet) {\n                Object g = descRead(descObj, descMap, \"get\", cc);\n                if (g != Terms.UNDEFINED) {\n                    if (!(g instanceof JsCallable c)) {\n                        throw JsErrorException.typeError(\"Getter must be a function\");\n                    }\n                    newGetter = c;","sourceCodeStart":596,"sourceCodeEnd":632,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsObjectConstructor.java#L596-L632","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst cfg = Object.freeze({ host: 'x' });\nObject.defineProperty(cfg, 'port', { value: 8080 }); // TypeError\n// after\nconst cfg = Object.freeze({ host: 'x' });\nconst cfg2 = { ...cfg, port: 8080 }; // extend via copy instead","handlingStrategy":"validation","validationCode":"if (!Object.isExtensible(obj)) throw new Error('target is not extensible; cannot add ' + key);","typeGuard":"function canDefineNew(obj, key) { return obj != null && Object.isExtensible(obj) && !(key in obj); }","tryCatchPattern":"try { Object.defineProperty(obj, key, desc); } catch (e) { if (String(e.message).includes('not extensible')) obj = { ...obj, [key]: desc.value }; else throw e; }","preventionTips":["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"],"tags":["javascript","immutability","object","defineproperty"],"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"}