karatelabs/karate · error · JsErrorException

Cannot delete property

Error message

Cannot delete property '{name}' of [object Object]

What it means

failNotConfigurable implements strict-mode [[Delete]] rejection for string-keyed properties: deleting an existing non-configurable property throws a TypeError, whereas sloppy delete would just return false. The message includes the receiver's toStringTag for context.

Solutions

  1. Avoid deleting; assign undefined (and/or null out the value) instead if configurability can't change
  2. Redefine the property with configurable:true first (possible only if it is currently configurable), then delete
  3. Clone the object minus the key ({[k]: v} rest spread / structuredClone + delete on the copy)

Example fix

// before
var o = Object.freeze({token: 'abc'});
delete o.token; // TypeError
// after
var o = {token: 'abc'};
var {token, ...rest} = o; // non-mutating removal
Defensive patterns

Strategy: try-catch

Validate before calling

var d = Object.getOwnPropertyDescriptor(o, name); if (d && !d.configurable) throw new TypeError('prop not configurable: ' + name);

Type guard

function isConfigurableProp(o, name) { var d = Object.getOwnPropertyDescriptor(o, name); return !d || d.configurable === true; }

Try / catch

try { delete o[name]; } catch (e) { if (String(e).includes('Cannot delete property')) { o[name] = undefined; } else { throw e; } }

Prevention

When it happens

Trigger: Strict-mode delete obj.prop where prop is an own non-configurable property (Object.defineProperty default, frozen/sealed object properties, or built-in slots).

Common situations: Deleting properties of a frozen object during cleanup; Object.defineProperty used without configurable:true; sanitizing third-party objects that expose non-configurable fields; strict-mode code where sloppy deletes previously 'succeeded' silently.

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsObject.java:488

    /** True iff {@code name} has a non-tombstoned own slot (excludes intrinsics). */
    boolean ownContainsKey(String name) {
        PropertySlot s = props == null ? null : props.get(name);
        return s != null && !s.tombstoned;
    }

    /** Strict-mode [[Set]] rejection: assigning a non-writable / frozen prop. */
    static void failReadOnly(String name) {
        throw JsErrorException.typeError("Cannot assign to read only property '" + name + "'");
    }

    /** Strict-mode [[Set]] rejection: adding a key to a non-extensible object. */
    static void failNotExtensible(String name) {
        throw JsErrorException.typeError("Cannot add property " + name + ", object is not extensible");
    }

    /** Strict-mode [[Delete]] rejection: removing a non-configurable property. */
    static void failNotConfigurable(String name) {
        throw JsErrorException.typeError("Cannot delete property '" + name + "' of " + "[object Object]");
    }

    @Override
    public void putMember(String name, Object value) {
        putMember(name, value, null, false);
    }

    @Override
    public void putMember(String name, Object value, CoreContext ctx, boolean strict) {
        if ("__proto__".equals(name)) {
            if (value instanceof ObjectLike proto) {
                this.__proto__ = proto;
            } else if (value == null) {
                this.__proto__ = null;
            }
            return;
        }
        // Frozen: ignore all writes (sloppy); strict throws. Non-extensible:

View on GitHub (pinned to a22eb90246)