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

  1. Remove value/writable keys from descriptors that specify get/set (or vice versa)
  2. When merging descriptors, strip incompatible fields based on whether the result should be data or accessor
  3. 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 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


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 not

View on GitHub (pinned to a22eb90246)