{"record":{"id":"e3f156c941e7ff9e","repo":"karatelabs/karate","slug":"cannot-delete-property-sym","errorCode":null,"errorMessage":"Cannot delete property '{sym}'","messagePattern":"Cannot delete property '(.+?)'","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsObject.java","lineNumber":299,"sourceCode":"            s = as;\n        } else {\n            s = new AccessorSlot(sym.toString());\n            symbols.put(sym, s);\n        }\n        s.getter = getter;\n        s.setter = setter;\n        s.attrs = attrs;\n        s.tombstoned = false;\n    }\n\n    boolean removeSymbol(JsSymbol sym, boolean strict) {\n        PropertySlot s = ownSymbolSlot(sym);\n        if (s == null) {\n            return true;\n        }\n        if (!s.isConfigurable()) {\n            if (strict) {\n                throw JsErrorException.typeError(\"Cannot delete property '\" + sym + \"'\");\n            }\n            return false;\n        }\n        symbols.remove(sym);\n        return true;\n    }\n\n    /** Own enumerable symbol keys — the partition §7.3.26 CopyDataProperties\n     *  and {@code Object.assign} copy. */\n    List<JsSymbol> ownEnumerableSymbols() {\n        if (symbols == null) {\n            return List.of();\n        }\n        List<JsSymbol> out = new ArrayList<>(symbols.size());\n        for (Map.Entry<JsSymbol, PropertySlot> e : symbols.entrySet()) {\n            PropertySlot slot = e.getValue();\n            if (!slot.tombstoned && slot.isEnumerable()) {\n                out.add(e.getKey());","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsObject.java#L281-L317","documentation":"Strict-mode delete on a property whose configurable attribute is false throws a TypeError per [[Delete]]; sloppy mode returns false silently. Karate's removeSymbol applies this to symbol-keyed own properties.","triggerScenarios":"Strict-mode delete obj[sym] where sym names an own symbol property defined with configurable:false (e.g. via Object.defineProperty defaults) or created as non-configurable.","commonSituations":"Object.defineProperty without configurable:true (defaults to false); built-in/foreign objects exposing non-configurable symbol slots; cleanup code removing injected metadata in strict mode.","solutions":["Define the symbol property with configurable:true if deletion must work","Redefine the property to configurable:true before deleting","Skip the delete (or guard with a configurability check) and treat it as intentional permanence"],"exampleFix":"// before\nObject.defineProperty(o, sym, {value: 1});\ndelete o[sym]; // TypeError\n// after\nObject.defineProperty(o, sym, {value: 1, configurable: true});\ndelete o[sym];","handlingStrategy":"type-guard","validationCode":"var d = Object.getOwnPropertyDescriptor(o, sym); if (d && !d.configurable) throw new TypeError('symbol prop not configurable');","typeGuard":"function isConfigurableSym(o, sym) { var d = Object.getOwnPropertyDescriptor(o, sym); return !d || d.configurable === true; }","tryCatchPattern":"try { delete o[sym]; } catch (e) { if (String(e).includes('Cannot delete property')) { o[sym] = undefined; } else { throw e; } }","preventionTips":["Always pass configurable:true in Object.defineProperty when lifecycle deletion is planned","Avoid delete on built-in or frozen slots; null the value instead","Check descriptor configurability before deleting in strict code"],"tags":["javascript","strict-mode","typeerror","delete-operator","karate-js"],"backgroundTag":"delete-non-configurable-property","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}