{"record":{"id":"1c6a4431b4cf1258","repo":"flowable/flowable-engine","slug":"cannot-set-value-of-property-it-s-readonly","errorCode":null,"errorMessage":"Cannot set value of '${property}', it's readonly!","messagePattern":"Cannot set value of '(.+?)', it's readonly!","errorType":"exception","errorClass":"ActivitiException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/el/ReadOnlyMapELResolver.java","lineNumber":56,"sourceCode":"        if (base == null) {\n            if (wrappedMap.containsKey(property)) {\n                context.setPropertyResolved(true);\n                return wrappedMap.get(property);\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean isReadOnly(ELContext context, Object base, Object property) {\n        return true;\n    }\n\n    @Override\n    public void setValue(ELContext context, Object base, Object property, Object value) {\n        if (base == null) {\n            if (wrappedMap.containsKey(property)) {\n                throw new ActivitiException(\"Cannot set value of '\" + property + \"', it's readonly!\");\n            }\n        }\n    }\n\n    @Override\n    public Class<?> getCommonPropertyType(ELContext context, Object arg) {\n        return Object.class;\n    }\n\n    @Override\n    public Class<?> getType(ELContext context, Object arg1, Object arg2) {\n        return Object.class;\n    }\n}\n","sourceCodeStart":38,"sourceCodeEnd":71,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/el/ReadOnlyMapELResolver.java#L38-L71","documentation":"ReadOnlyMapELResolver exposes a wrapped Map to EL as read-only. Its setValue throws ActivitiException whenever the EL expression attempts to write a property that exists in the wrapped map, enforcing that the map cannot be modified from expressions.","triggerScenarios":"An EL expression performing an assignment (e.g. ${myMap.key = 'value'} or c:set-style writes) on a base object that is the read-only map with a matching key.","commonSituations":"Scripts/delegates trying to mutate engine-provided read-only maps (e.g. process variables snapshots, variables maps passed read-only into expressions); accidentally confusing a read-only view with a variable scope.","solutions":["Remove the assignment from the expression; read-only maps are for reads only","Write through runtimeService.setVariable / execution.setVariable instead of EL assignment","If mutation is intended, pass a mutable map or a real VariableScope rather than the read-only resolver"],"exampleFix":"// before (EL)\n${myVar = 'newValue'}\n// after (Java)\nruntimeService.setVariable(executionId, \"myVar\", \"newValue\");","handlingStrategy":"validation","validationCode":"// Validate the EL does not assign to read-only map keys before evaluation\nif (expression != null && expression.matches(\".*\\\\$\\\\{[^}]*=[^}]*\\\\}.*\")) {\n    throw new IllegalArgumentException(\"Assignments in EL are not allowed on read-only maps\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    expressionManager.createExpression(expr).getValue(scope);\n} catch (ActivitiException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"it's readonly\")) {\n        // write via runtimeService.setVariable instead\n    }\n}","preventionTips":["Never assign to keys of maps exposed through ReadOnlyMapELResolver in expressions","Use runtimeService/execution setVariable APIs for writes","Distinguish read-only snapshots from mutable variable scopes in expression design"],"tags":["readonly","expression-language","el-resolver"],"backgroundTag":"invalid-argument-value","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}