karatelabs/karate · error · JsErrorException
Invalid property descriptor. Cannot both specify accessors…
Error message
Invalid property descriptor. Cannot both specify accessors and a value or writable attribute
What it means
A property descriptor may not specify both accessor fields (get/set) and data fields (value/writable) at the same time. The spec's ToPropertyDescriptor rejects such a descriptor with a TypeError, and this engine reproduces that message exactly. This is a descriptor validation error — it fires regardless of the target property's current state.
Solutions
- Remove value/writable keys from descriptors that specify get/set (or vice versa)
- When merging descriptors, strip incompatible fields based on whether the result should be data or accessor
- Define the property twice if you truly need both forms (define accessor, then a separate object for data)
Example fix
// before
Object.defineProperty(obj, 'x', {get: () => v, value: 1}); // throws
// after
Object.defineProperty(obj, 'x', {get: () => v, configurable: true}); // accessor only Defensive patterns
Strategy: validation
Validate before calling
const hasAccessor = 'get' in desc || 'set' in desc;
const hasData = 'value' in desc || 'writable' in desc;
if (hasAccessor && hasData) throw new TypeError('descriptor cannot mix accessor and data fields'); Type guard
function isValidDescriptor(desc) {
const a = 'get' in desc || 'set' in desc;
const d = 'value' in desc || 'writable' in desc;
return !(a && d);
} Try / catch
try { Object.defineProperty(obj, key, desc); }
catch (e) { if (String(e).includes('Cannot both specify accessors')) { const {value, writable, ...accessorOnly} = desc; Object.defineProperty(obj, key, accessorOnly); } else { throw e; } } Prevention
- When merging descriptors, strip data fields if get/set are present
- Keep separate constants for data vs accessor descriptor templates
- Test dynamic descriptor construction for field overlap
When it happens
Trigger: Object.defineProperty(obj, 'x', {get: fn, value: 1}), {set: fn, writable: false}, or a dynamically merged descriptor where one source contributes get/set and another contributes value/writable.
Common situations: Merging default descriptors with accessor configs (Object.assign({get}, {value})); copying fields from two different property definitions; refactoring a data property to a getter while leaving the old value/writable keys in place.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Property descriptor must be an object
- NoSuchElementException
- 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/909432fa4773f906.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsObjectConstructor.java:600
// a {@code writable} field. Raw Java Maps have no proto — fall
// back to {@code containsKey}.
boolean hasGet = descHas(descObj, descMap, "get");
boolean hasSet = descHas(descObj, descMap, "set");
boolean hasValue = descHas(descObj, descMap, "value");
boolean hasWritable = descHas(descObj, descMap, "writable");
boolean hasEnumerable = descHas(descObj, descMap, "enumerable");
boolean hasConfigurable = descHas(descObj, descMap, "configurable");
boolean isAccessor = hasGet || hasSet;
boolean isData = hasValue || hasWritable;
// Generic descriptor — none of get/set/value/writable specified.
// Per spec ValidateAndApplyPropertyDescriptor: a generic descriptor
// preserves the descriptor *type* of the existing slot. The
// accessor → data overwrite (which clobbers the get/set fields) only
// 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 notView on GitHub (pinned to a22eb90246)