flowable/flowable-engine · error · PropertyNotWritableException

Cannot write property: ${property}

Error message

Cannot write property: ${property}

What it means

Flowable's bundled CouldNotResolvePropertyELResolver throws PropertyNotWritableException from setValue for any property assignment, because it is a fallback resolver that considers all unresolved property writes unwritable.

Source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/javax/el/CouldNotResolvePropertyELResolver.java:47

        return Object.class;
    }

    @Override
    public Object getValue(ELContext context, Object base, Object property) {
        if (base != null) {
            throw new PropertyNotFoundException("Could not find property " + property + " in " + base.getClass());
        }
        return null;
    }

    @Override
    public boolean isReadOnly(ELContext context, Object base, Object property) {
        return false;
    }

    @Override
    public void setValue(ELContext context, Object base, Object property, Object value) {
        throw new PropertyNotWritableException("Cannot write property: " + property);
    }
}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Do not assign variables via EL expressions; use execution/task variable APIs (setVariable)
  2. Check that the target bean exposes a writable setter so another resolver resolves the write first
  3. Review ELResolver chain ordering so the proper resolver handles writes

Example fix

// before (delegate)
execution.setVariable("x", ${someBean.value = 10})
// after
execution.setVariable("x", 10);
Defensive patterns

Strategy: try-catch

Validate before calling

// Avoid EL writes entirely; detect assignment expressions statically
if (exprText.contains("=")) throw new IllegalArgumentException("EL assignment not supported: " + exprText);

Try / catch

try {
  resolver.setValue(ctx, base, property, value);
} catch (PropertyNotWritableException e) {
  execution.setVariable(String.valueOf(property), value);
}

Prevention

When it happens

Trigger: Any EL expression that attempts to assign a value, e.g. ${myBean.someProperty = 5}, that was not resolved by an earlier resolver in the chain.

Common situations: Trying to set variables via EL expressions in BPMN/CDI-like contexts where variable assignment should go through the engine's variable APIs; misconfigured resolver chains.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/281f0404febdebec. Report an issue: GitHub.