{"record":{"id":"92baddd7a971ab53","repo":"flowable/flowable-engine","slug":"resolver-is-read-only-92badd","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/javax/el/BeanELResolver.java","lineNumber":172,"sourceCode":"\t\t\treturn invoke(m, base, (Object[]) null);\n\t\t} catch (InvocationTargetException e) {\n\t\t\tThrowable cause = e.getCause();\n\t\t\tUtil.handleThrowable(cause);\n            throw new ELException(\"Error reading '\" + property + \"' on type '\" + base.getClass().getName() + \"'\", cause);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ELException(e);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void setValue(ELContext context, Object base, Object property, Object value) {\n\t\tObjects.requireNonNull(context, \"context is null\");\n\t\tif (base == null || property == null) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (readOnly) {\n\t\t\tthrow new PropertyNotWritableException(\"resolver is read-only\");\n\t\t}\n\t\tBeanProperty beanProperty = property(base, property);\n\n\t\tif (beanProperty == null) {\n\t\t\treturn;\n\t\t}\n\n\t\tMethod method = beanProperty.write(base);\n\t\tif (method == null) {\n\t\t\tthrow new PropertyNotWritableException(\"Cannot write property: '\" + property + \"' on type \" + base.getClass().getName());\n\t\t}\n\t\tcontext.setPropertyResolved(base, property);\n\t\ttry {\n\t\t\tinvoke(method, base, value);\n\t\t} catch (InvocationTargetException e) {\n\t\t\tThrowable cause = e.getCause();\n\t\t\tUtil.handleThrowable(cause);\n\t\t\tthrow new ELException(\"Error '\" + property + \"' on type '\" + base.getClass().getName() + \"'\", cause);","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/javax/el/BeanELResolver.java#L154-L190","documentation":"BeanELResolver.setValue throws PropertyNotWritableException(\"resolver is read-only\") when a value is assigned through an EL expression on a resolver that was constructed with readOnly=true. The resolver refuses all writes regardless of the target bean.","triggerScenarios":"Evaluating an assignment expression like ${bean.name = 'x'} (or calling setValue directly) against a BeanELResolver created as new BeanELResolver(true) — e.g. a shared read-only resolver used in Flowable's EL context.","commonSituations":"Reusing a read-only resolver configured for safe expression evaluation in a context that also attempts writes; accidental assignment syntax in templates meant to be read-only.","solutions":["Remove the assignment from the expression; use reads only.","If writes are legitimately needed, construct the resolver with readOnly=false.","Perform the mutation in code (bean setter) rather than inside the EL expression."],"exampleFix":"// before\nELResolver r = new BeanELResolver(true); // read-only\n// after\nELResolver r = new BeanELResolver(false); // only if writes are intended","handlingStrategy":"validation","validationCode":"if (needsWrites) resolver = new BeanELResolver(false); // else keep readOnly=true and never emit assignment expressions","typeGuard":null,"tryCatchPattern":"try { resolver.setValue(ctx, base, prop, val); } catch (PropertyNotWritableException e) { /* route write elsewhere or rebuild resolver writable */ }","preventionTips":["Keep assignment expressions out of read-only evaluation contexts","Document which resolvers in the chain are read-only","Mutate beans in code, not in EL expressions"],"tags":["el","bean","read-only","expression-language"],"backgroundTag":"permission-denied","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"}