{"record":{"id":"e36bd6d1c31e51c7","repo":"karatelabs/karate","slug":"assignment-to-constant-frametable-names-idx","errorCode":null,"errorMessage":"assignment to constant: ${frameTable.names[idx]}","messagePattern":"assignment to constant: (.+?)","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/CoreContext.java","lineNumber":601,"sourceCode":"        // Sibling closures sharing the same Slot reference see the new\n        // value immediately.\n        s.value = value;\n        if (root.listener != null) {\n            root.listener.onBind(BindEvent.assign(key, value, oldValue, this, node));\n        }\n    }\n\n    /** Slot analogue of the post-resolve half of {@link #update} — same const\n     *  check, same name inference, same BindEvent. A TDZ slot behaves like the\n     *  store's uninitialized binding: the write initializes (const included),\n     *  and the event reports undefined as the old value, which is what the\n     *  store held. Callers must have checked the slot is not UNDECLARED. */\n    void updateSlot(int idx, Object value, Node node) {\n        Object oldValue = frame[idx];\n        if (oldValue == SlotTable.TDZ) {\n            oldValue = Terms.UNDEFINED;\n        } else if (frameTable.kinds[idx] == SlotTable.KIND_CONST) {\n            throw JsErrorException.typeError(\"assignment to constant: \" + frameTable.names[idx]);\n        }\n        if (value instanceof JsFunction fn && (fn.name == null || fn.name.isEmpty())) {\n            fn.name = frameTable.names[idx];\n        }\n        frame[idx] = value;\n        if (root.listener != null) {\n            root.listener.onBind(BindEvent.assign(frameTable.names[idx], value, oldValue, this, node));\n        }\n    }\n\n    private void assignImplicitGlobal(String key, Object value, Node node) {\n        // ES6 non-strict implicit global: writes go straight to the engine's\n        // single shared Bindings (root and script context point at the same\n        // instance). No parent walk needed.\n        root.bindings.putMember(key, value, null, true);\n        if (root.listener != null) {\n            root.listener.onBind(BindEvent.declare(key, value, BindScope.VAR, this, node));\n        }","sourceCodeStart":583,"sourceCodeEnd":619,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/CoreContext.java#L583-L619","documentation":"Same TypeError as the by-name path but raised from the slot-indexed fast path (CoreContext.updateSlot): the engine resolved a local slot whose kind is KIND_CONST and the script attempted to store a new value into it. TDZ slots are exempt (they fail elsewhere); only initialized consts trigger this. The message names the slot's declared identifier.","triggerScenarios":"Assignment, compound assignment, or pre/post increment/decrement (updateSlot is called by update, set, compound, logicalCompound, postIncDec, preIncDec) targeting a `const` local, e.g. `const total = 0; total += 5;` or `const c = []; c++`.","commonSituations":"Incrementing a const counter; `+=` on a const accumulator; refactor scripts where a `let` was turned into `const` but mutation code remained; generated/transpiled code emitting stores to const slots.","solutions":["Change the declaration from const to let where the value must be reassigned","Use a separate mutable variable and keep the const as the fixed reference","Replace increment/compound ops on consts with immutable expressions assigned to a new const","For collections, mutate contents (`arr.push(x)`) rather than rebinding the const binding itself"],"exampleFix":"// before\nconst total = 0;\ntotal += item.price;\n// after\nlet total = 0;\ntotal += item.price;","handlingStrategy":"validation","validationCode":"let total = 0; // any variable later mutated must be let, not const","typeGuard":null,"tryCatchPattern":"try { total += 1; } catch (e) { if (String(e).indexOf('assignment to constant') >= 0) { /* redeclare with let */ } else { throw e; } }","preventionTips":["Audit pre/post ++ and compound += on const declarations","Run lint with no-const-assign over karate JS snippets","Keep accumulation in let variables; keep totals-of-record in const"],"tags":["javascript","const","typeerror","assignment"],"backgroundTag":"invalid-state-transition","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"}