{"record":{"id":"fef894cdf10102bd","repo":"karatelabs/karate","slug":"cannot-redefine-property","errorCode":null,"errorMessage":"Cannot redefine property: ","messagePattern":"Cannot redefine property: ","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsObjectConstructor.java","lineNumber":489,"sourceCode":"\n    /**\n     * Spec §10.1.6.3 ValidateAndApplyPropertyDescriptor — the rejection half, for\n     * an existing NON-configurable property. Only two changes are legal: a\n     * same-value redefine, and narrowing {@code writable} true → false on a data\n     * property. Shared by the string- and symbol-keyed {@code defineProperty}\n     * paths so the two cannot drift. {@code newValue} is a supplier because\n     * reading the descriptor's {@code value} can run a getter, which must not\n     * happen on a branch that doesn't need it.\n     */\n    private static void validateNonConfigurableRedefine(\n            Object label, boolean existingIsAccessor, AccessorSlot existingAcc, Object existingValue,\n            byte oldAttrs, byte newAttrs, boolean isAccessor, boolean isData,\n            boolean hasConfigurable, boolean hasEnumerable, boolean hasGet, boolean hasSet,\n            boolean hasValue, JsCallable newGetter, JsCallable newSetter,\n            java.util.function.Supplier<Object> newValue) {\n        // configurable cannot flip false → true\n        if (hasConfigurable && (newAttrs & JsObject.CONFIGURABLE) != 0) {\n            throw JsErrorException.typeError(\"Cannot redefine property: \" + label);\n        }\n        // enumerable cannot change\n        if (hasEnumerable && ((oldAttrs ^ newAttrs) & JsObject.ENUMERABLE) != 0) {\n            throw JsErrorException.typeError(\"Cannot redefine property: \" + label);\n        }\n        // Cannot switch between data and accessor shapes\n        if (existingIsAccessor != isAccessor && (isAccessor || isData)) {\n            throw JsErrorException.typeError(\"Cannot redefine property: \" + label);\n        }\n        if (existingIsAccessor && isAccessor) {\n            // Accessor→accessor: get / set cannot change unless they match the existing.\n            JsCallable mergedGet = hasGet ? newGetter : existingAcc.getter;\n            JsCallable mergedSet = hasSet ? newSetter : existingAcc.setter;\n            if (mergedGet != existingAcc.getter || mergedSet != existingAcc.setter) {\n                throw JsErrorException.typeError(\"Cannot redefine property: \" + label);\n            }\n        } else if (!existingIsAccessor && isData) {\n            // Data → data on non-configurable: writable cannot flip false → true.","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsObjectConstructor.java#L471-L507","documentation":"Object.defineProperty attempted to redefine an existing non-configurable property in a forbidden way: flipping configurable back to true, changing the enumerable flag, or switching between data and accessor forms. The spec (§ ordinaryDefineOwnProperty) forbids all of these once configurable is false, so the engine throws a TypeError.","triggerScenarios":"Defining a property twice where the first defineProperty used configurable:false and the second changes configurable/enumerable or swaps value-data for get/set; redefining intrinsics or sealed/frozen object members.","commonSituations":"Making a property read-only (configurable:false) then later trying to attach a getter to it; applying a property-definition script twice against the same object; freezing an object then modifying its shape.","solutions":["Remove the second definition or make it compatible with the original descriptor (same data/accessor kind, same enumerable, no configurable:true).","Don't pass configurable:false unless the property must be permanently locked; keep configurable:true so later redefinition is legal.","Use Reflect.defineProperty inside a check with Object.getOwnPropertyDescriptor to compare the existing descriptor before defining.","Recreate the object instead of redefining locked properties."],"exampleFix":"// before\nObject.defineProperty(o, 'id', {value: 1, configurable: false});\nObject.defineProperty(o, 'id', {get: () => 1}); // throws\n// after\nObject.defineProperty(o, 'id', {value: 1, configurable: true});\nObject.defineProperty(o, 'id', {get: () => 1}); // ok","handlingStrategy":"try-catch","validationCode":"var desc = Object.getOwnPropertyDescriptor(o, 'id');\nif (desc && !desc.configurable) {\n  throw new Error('id is non-configurable; cannot redefine');\n}","typeGuard":"function isRedefinable(o, key) { var d = Object.getOwnPropertyDescriptor(o, key); return !d || d.configurable; }","tryCatchPattern":"try { Object.defineProperty(o, 'id', newDesc); } catch (e) { if (String(e).indexOf('Cannot redefine property') !== -1) { /* keep original descriptor or rebuild object */ } else { throw e; } }","preventionTips":["Keep configurable:true unless permanently locking a property","Inspect the existing descriptor with Object.getOwnPropertyDescriptor before defineProperty","Never re-run definition scripts against frozen/sealed objects","Keep data vs accessor shape consistent across redefinitions"],"tags":["javascript","typeerror","defineproperty","property-descriptor"],"backgroundTag":"invalid-state-transition","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"}