{"record":{"id":"e10e275ae0817acc","repo":"flowable/flowable-engine","slug":"resolver-is-read-only-e10e27","errorCode":null,"errorMessage":"resolver is read-only","messagePattern":"resolver is read-only","errorType":"exception","errorClass":"PropertyNotWritableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/el/JsonNodeELResolver.java","lineNumber":290,"sourceCode":"     */\n    @Override\n    public void setValue(ELContext context, Object base, Object property, Object value) {\n        if (context == null) {\n            throw new NullPointerException(\"context is null\");\n        }\n        if (isResolvable(base)) {\n            FlowableJsonNode baseNode = JsonUtil.asFlowableJsonNode(base);\n            if (baseNode instanceof FlowableObjectNode objectNode) {\n                setValue(context, objectNode, property, value);\n            } else if (baseNode instanceof FlowableArrayNode arrayNode) {\n                setValue(context, arrayNode, property, value);\n            }\n        }\n    }\n\n    protected void setValue(ELContext context, FlowableObjectNode node, Object property, Object value) {\n        if (readOnly) {\n            throw new PropertyNotWritableException(\"resolver is read-only\");\n        }\n\n        String propertyName = property.toString();\n        if (value instanceof BigDecimal bigDecimal) {\n            node.put(propertyName, bigDecimal);\n\n        } else if (value instanceof Boolean booleanValue) {\n            node.put(propertyName, booleanValue);\n\n        } else if (value instanceof Integer integerValue) {\n            node.put(propertyName, integerValue);\n        } else if (value instanceof Long longValue) {\n            node.put(propertyName, longValue);\n\n        } else if (value instanceof Double doubleValue) {\n            node.put(propertyName, doubleValue);\n\n        } else if (JsonUtil.isJsonNode(value)) {","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/el/JsonNodeELResolver.java#L272-L308","documentation":"The object-node branch of JsonNodeELResolver.setValue throws PropertyNotWritableException('resolver is read-only') when the resolver was constructed with readOnly=true and an object property write is attempted. Read-only resolvers are used in Flowable to protect expression evaluation from mutating underlying data.","triggerScenarios":"Evaluating an expression that assigns a value to a JSON object property (e.g. ${jsonVar.field = x}) while the EL resolver was created read-only (the default in several Flowable evaluation paths).","commonSituations":"Using an expression that mutates a JSON variable inside a read-only evaluation context (e.g. condition/listener expressions in BPMN); calling ValueExpression.setValue on a read-only resolver configuration.","solutions":["Use a JsonNodeELResolver constructed with readOnly=false for the write path","Rewrite the expression to compute a value instead of assigning to the JSON variable","Perform the mutation via Flowable variable-service APIs (setVariable / JsonUtil) instead of EL assignment"],"exampleFix":"// before\nJsonNodeELResolver resolver = new JsonNodeELResolver(true); // read-only\nexpression.setValue(value, ctx); // PropertyNotWritableException\n// after\nJsonNodeELResolver resolver = new JsonNodeELResolver(false);\nexpression.setValue(value, ctx);","handlingStrategy":"validation","validationCode":"if (expressionContainsAssignment(exprText) && resolverReadOnly) { throw new IllegalStateException(\"Cannot assign to JSON properties with a read-only EL resolver: \" + exprText); }","typeGuard":null,"tryCatchPattern":"try { expr.setValue(value, ctx); } catch (PropertyNotWritableException e) { // fall back to variable-service mutation\n  execution.setVariable(varName, updatedJson); }","preventionTips":["Know which Flowable evaluation contexts are read-only and never write from expressions there","Mutate JSON variables via execution.setVariable/JsonUtil instead of EL assignment","Search process definitions for '=' assignment expressions when configuring read-only resolvers"],"tags":["java","el","read-only"],"backgroundTag":"unsupported-operation","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"}