{"record":{"id":"692ea507434ad249","repo":"karatelabs/karate","slug":"optional-chain-cannot-be-the-operand-of-postfix","errorCode":null,"errorMessage":"optional chain cannot be the operand of postfix ++/--","messagePattern":"optional chain cannot be the operand of postfix \\+\\+/--","errorType":"exception","errorClass":"ParserException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/parser/JsParser.java","lineNumber":523,"sourceCode":"                Node base = stripExprWrappers(node.size() > 0 ? node.getFirst() : null);\n                if (base != null) {\n                    boolean unaryBase = switch (base.type) {\n                        case DELETE_EXPR, TYPEOF_EXPR, UNARY_EXPR, AWAIT_EXPR -> true;\n                        case MATH_PRE_EXPR -> base.size() > 0 && base.getFirst().isToken()\n                                && (base.getFirst().token.type == PLUS || base.getFirst().token.type == MINUS);\n                        default -> false;\n                    };\n                    if (unaryBase) {\n                        throw new ParserException(\"unary expression cannot be the base of '**'; wrap it in parentheses\");\n                    }\n                }\n            }\n            case MATH_POST_EXPR -> {\n                // children: [operand, ++/--]\n                if (node.size() > 0) {\n                    Node operand = node.getFirst();\n                    if (sawOptionalChain && subtreeContainsOptionalChain(operand)) {\n                        throw new ParserException(\"optional chain cannot be the operand of postfix ++/--\");\n                    }\n                    checkSimpleAssignmentTarget(operand, \"operand of postfix update\", false);\n                }\n            }\n            case MATH_PRE_EXPR -> {\n                // children: [op, operand] — only ++/-- need a valid update target;\n                // unary +/- have no assignment side and parse the same shape.\n                if (node.size() > 1) {\n                    Node op = node.getFirst();\n                    if (op.isToken() && (op.token.type == PLUS_PLUS || op.token.type == MINUS_MINUS)) {\n                        Node operand = node.get(1);\n                        if (sawOptionalChain && subtreeContainsOptionalChain(operand)) {\n                            throw new ParserException(\"optional chain cannot be the operand of prefix ++/--\");\n                        }\n                        checkSimpleAssignmentTarget(operand, \"operand of prefix update\", false);\n                    }\n                }\n            }","sourceCodeStart":505,"sourceCodeEnd":541,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/parser/JsParser.java#L505-L541","documentation":"Postfix `++`/`--` require a valid simple assignment target; an optional chain (`a?.b++`) is never one. The Karate JS parser throws this early error when the postfix-update operand contains an optional chain. Split the read and the write instead.","triggerScenarios":"Parsing `a?.b++` or `f()?.counter--`, detected in earlyErrorNodeChecks for MATH_POST_EXPR nodes whose operand subtree contains an optional chain.","commonSituations":"Incrementing a counter on a possibly-null object found via optional chaining; compact loop code written assuming `?.` composes with updates; mechanical rewrites from `a && a.b++`.","solutions":["Guard with an if: `if (a) a.b++;`","Split the operation: `const v = a?.b; if (a) a.b = v + 1;`","Use a definite reference when nullability is already handled: `a.b++`."],"exampleFix":"// before\ncounter?.count++;\n// after\nif (counter) counter.count++;","handlingStrategy":"validation","validationCode":"// reject optional chains under postfix ++/--\nfunction validPostfixUpdate(src) { return !/\\?\\.[\\w$]+\\s*(\\+\\+|--)/.test(src); }","typeGuard":null,"tryCatchPattern":"try { karate.eval(expr); } catch (e) { if (String(e).includes('optional chain cannot be the operand of postfix')) { /* guard with if */ } }","preventionTips":["Treat `?.` results as read-only values, never update targets.","Guard updates with an explicit null check.","Enable lint rules that flag assignment/update on optional chains."],"tags":["javascript","parser","syntax-error","optional-chaining"],"backgroundTag":"javascript-syntax-error","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"}