flowable/flowable-engine · error · UnsupportedOperationException

Setting variable is not supported for read only delegate exe

Error message

Setting variable is not supported for read only delegate execution

What it means

ReadOnlyDelegatePlanItemInstance.setVariable throws UnsupportedOperationException by default: this plan-item-instance view is read-only and forbids variable mutation. The engine hands listeners/delegates a read-only facade when writes are not permitted (e.g. read-only evaluation contexts in CMMN), so variable writes must go through a writable execution instead.

Source

Thrown at modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/delegate/ReadOnlyDelegatePlanItemInstance.java:38

/**
 * @author Filip Hrisafov
 */
public interface ReadOnlyDelegatePlanItemInstance extends PlanItemInstance, VariableContainer {

    PlanItem getPlanItem();

    default PlanItemDefinition getPlanItemDefinition() {
        PlanItem planItem = getPlanItem();
        if (planItem != null) {
            return planItem.getPlanItemDefinition();
        }

        return null;
    }

    @Override
    default void setVariable(String variableName, Object variableValue) {
        throw new UnsupportedOperationException("Setting variable is not supported for read only delegate execution");
    }

    @Override
    default void setTransientVariable(String variableName, Object variableValue) {
        throw new UnsupportedOperationException("Setting transient variable is not supported for read only delegate execution");
    }

    @Override
    default void setLocalizedName(String localizedName) {
        throw new UnsupportedOperationException("Setting localized name is not supported for read only delegate execution");
    }
}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Write variables through engine services instead: cmmnRuntimeService.setVariable(caseInstanceId, name, value).
  2. Obtain a writable DelegatePlanItemInstance/ plan item instance from the runtime service and set variables there.
  3. Restructure the listener so variable changes happen in a phase/context where a mutable delegate is provided.
  4. Split shared code paths: for read-only contexts, read variables; perform writes only with an explicit id via the runtime service.

Example fix

// before
readOnlyPlanItemInstance.setVariable("status", "done"); // throws
// after
cmmnRuntimeService.setVariable(planItemInstance.getCaseInstanceId(), "status", "done");
Defensive patterns

Strategy: try-catch

Validate before calling

if (planItemInstance instanceof org.flowable.cmmn.api.delegate.ReadOnlyDelegatePlanItemInstance) {
    cmmnRuntimeService.setVariable(caseInstanceId, name, value);
} else {
    planItemInstance.setVariable(name, value);
}

Type guard

boolean isReadOnlyDelegate(DelegatePlanItemInstance p) {
    return p instanceof org.flowable.cmmn.api.delegate.ReadOnlyDelegatePlanItemInstance;
}

Try / catch

try {
    planItemInstance.setVariable(name, value);
} catch (UnsupportedOperationException e) {
    cmmnRuntimeService.setVariable(caseInstanceId, name, value); // writable path
}

Prevention

When it happens

Trigger: Calling setVariable(...) (or setTransientVariable) on a ReadOnlyDelegatePlanItemInstance passed into a CMMN plan-item listener/ delegate where the engine supplies a read-only delegate.

Common situations: Writing variables from a CMMN TaskListener/ PlanItemLifecycleListener that receives a read-only plan item instance; code shared between process (BPMN) and case (CMMN) listeners assuming mutable execution; version changes where listeners became read-only.

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/8e7b5558836228fb. Report an issue: GitHub.