{"record":{"id":"cdcfe6ffde73137d","repo":"flowable/flowable-engine","slug":"lambda-body-is-not-an-lvalue","errorCode":null,"errorMessage":"Lambda body is not an lvalue","messagePattern":"Lambda body is not an lvalue","errorType":"exception","errorClass":"ELException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/tree/impl/ast/AstLambdaExpression.java","lineNumber":88,"sourceCode":"     * Simple ValueExpression implementation that wraps an AstNode for lambda body evaluation.\n     */\n    private static class LambdaBodyValueExpression extends ValueExpression {\n        private final Bindings bindings;\n        private final AstNode body;\n\n        public LambdaBodyValueExpression(Bindings bindings, AstNode body) {\n            this.bindings = bindings;\n            this.body = body;\n        }\n\n        @Override\n        public Object getValue(ELContext context) throws ELException {\n            return body.eval(bindings, context);\n        }\n\n        @Override\n        public void setValue(ELContext context, Object value) throws ELException {\n            throw new ELException(\"Lambda body is not an lvalue\");\n        }\n\n        @Override\n        public boolean isReadOnly(ELContext context) throws ELException {\n            return true;\n        }\n\n        @Override\n        public Class<?> getType(ELContext context) throws ELException {\n            return Object.class;\n        }\n\n        @Override\n        public Class<?> getExpectedType() {\n            return Object.class;\n        }\n\n        @Override","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/tree/impl/ast/AstLambdaExpression.java#L70-L106","documentation":"The AST node representing a lambda expression's body does not support assignment. When setValue is called on the lambda body (e.g. via ValueExpression.setValue on an expression containing a lambda), the library throws ELException('Lambda body is not an lvalue') because a lambda result is a transient value, not a writable target.","triggerScenarios":"Calling ValueExpression.setValue(bindings, context, value) on an expression whose root is a lambda expression, e.g. assigning to ${x -> x + 1} or a lambda invocation result; using EL resolver set operations that walk into an AstLambdaExpression body.","commonSituations":"Misusing setValue on a computed expression instead of a variable; framework code (e.g. UI binding or process variable update) generically calls setValue on parsed expressions that happen to contain lambdas.","solutions":["Do not call setValue on lambda expressions; restructure so assignment targets a variable or bean property, e.g. ${myVar} not a lambda.","If you intended to update the variable captured by the lambda, set that variable directly via the ELContext VariableMapper or resolver instead.","Guard caller code with isReadOnly() before calling setValue and skip/skip-log read-only expressions."],"exampleFix":"// before\nexprNode.setValue(context, newValue); // expr is a lambda\n// after\n// set the underlying variable instead\ncontext.getVariableMapper().setVariable(\"myVar\", valueExpr);","handlingStrategy":"validation","validationCode":"if (valueExpression.isReadOnly(context)) {\n    throw new UnsupportedOperationException(\"Expression is read-only (lambda): \" + valueExpression.getExpressionString());\n}","typeGuard":"boolean isWritableTarget(ValueExpression ve, ELContext ctx) {\n    return ve != null && !ve.isLiteralText() && !ve.isReadOnly(ctx);\n}","tryCatchPattern":"try {\n    ve.setValue(context, newValue);\n} catch (ELException e) {\n    if (!e.getMessage().contains(\"not an lvalue\")) throw e;\n    // route assignment to a variable/property instead\n}","preventionTips":["Only call setValue on property expressions, never on lambdas or method calls","Check isReadOnly() before setValue","Assign captured variables via the VariableMapper, not the lambda body"],"tags":["el","expression-language","not-assignable"],"backgroundTag":"unsupported-operation","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}