{"record":{"id":"ade9a83a5db01401","repo":"karatelabs/karate","slug":"cannot-write-to-optional-call-expression","errorCode":null,"errorMessage":"cannot write to optional call expression","messagePattern":"cannot write to optional call expression","errorType":"exception","errorClass":"JsErrorException (typeError)","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/PropertyAccess.java","lineNumber":180,"sourceCode":"                Node key = node.get(2);\n                Object target = Interpreter.eval(node.getFirst(), context);\n                if (target == SHORT_CIRCUITED) return SHORT_CIRCUIT_SITE;\n                if (context.isStopped()) return null;\n                if (key.token.type == TokenType.PRIVATE_NAME) {\n                    return new AccessSite(target, null, false,\n                            PrivateAccess.resolve(key.getText(), context));\n                }\n                return new AccessSite(target, key.getText(), false, null, superReceiver);\n            }\n            if (second.type == NodeType.REF_BRACKET_EXPR) {\n                Object target = Interpreter.eval(node.getFirst(), context);\n                if (target == SHORT_CIRCUITED) return SHORT_CIRCUIT_SITE;\n                if (context.isStopped()) return null;\n                Object index = Interpreter.eval(second.get(2), context);\n                if (context.isStopped()) return null;\n                return new AccessSite(target, index, true, null, superReceiver);\n            }\n            throw JsErrorException.typeError(\"cannot write to optional call expression\");\n        }\n        // REF_BRACKET_EXPR\n        Object target = Interpreter.eval(node.getFirst(), context);\n        if (target == SHORT_CIRCUITED) return SHORT_CIRCUIT_SITE;\n        if (context.isStopped()) return null;\n        Object index = Interpreter.eval(node.get(2), context);\n        if (context.isStopped()) return null;\n        return new AccessSite(target, index, true, null, superReceiver);\n    }\n\n    /** Site read honoring a super receiver; the non-super shape delegates to\n     *  the ordinary index/name workers unchanged. */\n    private static Object siteRead(AccessSite site, CoreContext context) {\n        if (site.receiver == null) {\n            return site.isIndex\n                    ? getByIndex(site.target, site.key, false, context, false)\n                    : getByName(site.target, (String) site.key, false, context, false);\n        }","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/PropertyAccess.java#L162-L198","documentation":"When resolving the write target of an assignment, `PropertyAccess.resolveWriteSite` encountered an optional-call expression (`f?.()` on the LHS). Optional call expressions produce no reference to assign to, so the engine raises a TypeError instead of writing to nothing.","triggerScenarios":"An assignment whose left-hand side contains `?.()` or an optional-chain write target, e.g. `obj?.method() = value` or `a?.[b]?.() = x` parsed as a write site.","commonSituations":"Stray `=` in an expression where `==` was meant; generator/template code emitting optional-call LHS; hand-edited code leaving `?.()` in an assignment target.","solutions":["Remove the optional-call from the assignment LHS and assign to a plain reference or property.","Check for a typo: `=` used where `==`/`===` was intended.","If conditional invocation is intended, perform the call first and assign separately."],"exampleFix":"// before\nobj?.callback() = value; // TypeError: cannot write to optional call expression\n// after\nif (obj) obj.callback = value; // or: obj?.callback(value)","handlingStrategy":"validation","validationCode":"// reject optional-call on the left of '=' before evaluating\nconst badLhs = /\\?\\.\\s*\\([^)]*\\)\\s*=|\\?\\.[A-Za-z_$]+\\s*\\([^)]*\\)\\s*=/.test(src);\nif (badLhs) throw new Error('optional call cannot be an assignment target');","typeGuard":"function isPlainAssignTarget(expr) { return /^[A-Za-z_$][\\w$]*(\\.[A-Za-z_$][\\w$]*|\\[[^\\]]+\\])*$/.test(expr.trim()); }","tryCatchPattern":"try { engine.set(varName, value); } catch (e) { if (String(e.message).includes('cannot write to optional call expression')) { /* rewrite the expression */ } else { throw e; } }","preventionTips":["Assign only to identifiers or property references, never `?.()` results.","Check `=` vs `==` typos in embedded JS.","Run the expression through a linter before embedding in features."],"tags":["javascript","optional-chaining","type-error","assignment"],"backgroundTag":"invalid-argument-value","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}