karatelabs/karate · error · JsErrorException

Cannot add property , object is not extensible

Error message

Cannot add property {sym}, object is not extensible

What it means

Strict-mode [[Set]] on a new property requires the object to be extensible. When the receiver (or a prototype in the chain) is frozen, sealed, or non-extensible, adding a brand-new symbol-keyed property throws a TypeError in strict mode and is silently skipped otherwise.

Solutions

  1. Don't freeze/seal the object if new symbol properties must be added
  2. Pre-define the needed symbol properties before freezing
  3. Use a WeakMap keyed by the object instead of symbol properties for extra metadata

Example fix

// before
var cfg = Object.freeze({a: 1});
cfg[metaSym] = 'x'; // TypeError
// after
var meta = new WeakMap();
meta.set(cfg, 'x');
Defensive patterns

Strategy: validation

Validate before calling

if (!Object.isExtensible(o)) throw new TypeError('cannot add symbol prop to non-extensible object');

Type guard

function canAddProp(o) { return Object.isExtensible(o); }

Try / catch

try { o[sym] = v; } catch (e) { if (String(e).includes('not extensible')) { metaMap.set(o, v); } else { throw e; } }

Prevention

When it happens

Trigger: Strict-mode obj[newSymbol] = value where obj was produced by Object.freeze/Object.seal/Object.preventExtensions (or an ancestor with only inherited writable props blocked that way).

Common situations: Freezing config or shared objects and later attaching symbol-keyed caches/metadata; freezing objects in tests to detect accidental mutation; framework-created frozen objects.

Related errors


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

Appendix: source

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

                acc.write(this, value, ctx, strict);
                return;
            }
            if (!s.isWritable()) {
                if (strict) {
                    throw JsErrorException.typeError(
                            "Cannot assign to read only property '" + sym + "'");
                }
                return;
            }
            if (jo == this) {
                s.write(this, value, ctx, strict);
                return;
            }
            break; // inherited writable data property — shadow it with an own slot
        }
        if (frozen || sealed || nonExtensible) {
            if (strict) {
                throw JsErrorException.typeError(
                        "Cannot add property " + sym + ", object is not extensible");
            }
            return;
        }
        defineOwnSymbol(sym, value, PropertySlot.ATTRS_DEFAULT);
    }

    /** Low-level data-descriptor write for a symbol key — the
     *  {@code Object.defineProperty} seam. */
    void defineOwnSymbol(JsSymbol sym, Object value, byte attrs) {
        if (symbols == null) {
            symbols = new LinkedHashMap<>(4);
        }
        PropertySlot existing = symbols.get(sym);
        DataSlot s;
        if (existing instanceof DataSlot ds) {
            s = ds;
        } else {

View on GitHub (pinned to a22eb90246)