karatelabs/karate · error · JsErrorException

Object.defineProperty called on non-object

Error message

Object.defineProperty called on non-object

What it means

Object.defineProperty requires its first argument to be an object (ObjectLike) or a Map in this engine. Passing null, undefined, a primitive, or any other non-object type throws this TypeError, matching the spec's RequireObjectCoercible + Object check behavior.

Solutions

  1. Ensure the target is an object before calling: if (!target || typeof target !== 'object') create or load it first
  2. Fix the upstream code that produced null/undefined
  3. Use a Map if you intentionally want a key-value container (Map targets are accepted)

Example fix

// before
const target = config[objName]; // may be undefined
Object.defineProperty(target, 'x', {value: 1}); // throws if undefined
// after
const target = config[objName] ?? {};
Object.defineProperty(target, 'x', {value: 1});
Defensive patterns

Strategy: type-guard

Validate before calling

if (target == null || (typeof target !== 'object' && typeof target !== 'function')) throw new TypeError('defineProperty target must be an object');

Type guard

function isDefineTarget(t) { return t != null && (typeof t === 'object' || typeof t === 'function'); }

Try / catch

try { Object.defineProperty(target, key, desc); }
catch (e) { if (String(e).includes('called on non-object')) { target = {}; Object.defineProperty(target, key, desc); } else { throw e; } }

Prevention

When it happens

Trigger: Object.defineProperty(null, 'x', {}), Object.defineProperty(undefined, ...), Object.defineProperty(42, ...), or a variable holding null because an object lookup/factory returned nothing.

Common situations: Chained lookups like defineProperty(api?.config, ...) where config is missing; passing a JSON.parse result that came back null; refactoring left a primitive where an object was expected.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/f1746a389e50245c. Report an issue: GitHub.

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsObjectConstructor.java:550

        }
        desc.put("enumerable", slot.isEnumerable());
        desc.put("configurable", slot.isConfigurable());
        return new JsObject(desc);
    }

    /** Returns the own {@link AccessorSlot} at {@code key} when one exists,
     *  {@code null} otherwise (own data property, missing, or unsupported
     *  type). Scoped to own properties only — for the chain-walking variant
     *  see {@code PropertyAccess#findAccessorInChain}. */
    private static AccessorSlot ownAccessorSlot(Object obj, String key) {
        PropertySlot s = PropertyAccess.ownSlot(obj, key);
        return s instanceof AccessorSlot acc ? acc : null;
    }

    @SuppressWarnings("unchecked")
    Object defineProperty(Context context, Object[] args) {
        if (args.length < 1 || !(args[0] instanceof ObjectLike || args[0] instanceof Map)) {
            throw JsErrorException.typeError("Object.defineProperty called on non-object");
        }
        if (args.length < 2) {
            throw JsErrorException.typeError("property key is null");
        }
        if (args.length < 3 || args[2] == null || args[2] == Terms.UNDEFINED) {
            throw JsErrorException.typeError("Property descriptor must be an object");
        }
        // Spec ToPropertyKey: pass ctx so ObjectLike keys dispatch through
        // ToPrimitive(string) → ToString (test262 Object/defineProperty/
        // 15.2.3.6-2-{20,24,25,39,41,43,44,45,46,47,48} pass arrays / boxed
        // booleans / objects with overridden toString as the key arg).
        CoreContext keyCtx = context instanceof CoreContext c ? c : null;
        String prop = Terms.toPropertyKey(args[1], keyCtx);
        Object desc = args[2];
        ObjectLike descObj;
        Map<String, Object> descMap;
        if (desc instanceof ObjectLike ol) {
            descObj = ol;

View on GitHub (pinned to a22eb90246)