flowable/flowable-engine · error · UnsupportedOperationException

Not allowed to set variables in a bpmn error variable…

Error message

Not allowed to set variables in a bpmn error variable container

What it means

Thrown as UnsupportedOperationException by the anonymous BpmnErrorVariableContainer in ErrorPropagation.setVariable. The error variable container passed to BpmnError handling is read-only; Flowable forbids writing variables into it, so any setVariable call fails unconditionally.

Solutions

  1. Write variables on the DelegateExecution / process execution instead of the error variable container
  2. Read-only usage: only call getter methods (getVariable, getTenantId) on this container
  3. Capture values into the error event's variable mappings defined in the BPMN (in/out mappings) rather than calling setVariable
  4. Guard custom code with an instanceof/capability check before writing variables

Example fix

// before
errorVariableContainer.setVariable("reason", msg);
// after
((DelegateExecution) execution).setVariable("reason", msg);
Defensive patterns

Strategy: try-catch

Validate before calling

if (scope instanceof DelegateExecution) {
    ((DelegateExecution) scope).setVariable(name, value);
} else {
    throw new IllegalStateException("Refusing to write variables on read-only scope: " + scope.getClass());
}

Type guard

static boolean isWritableVariableScope(VariableScope scope) {
    return !(scope instanceof DelegateExecution) || scope instanceof ExecutionEntity;
}

Try / catch

try { scope.setVariable(name, value); }
catch (UnsupportedOperationException e) {
    if (e.getMessage().contains("bpmn error variable container")) {
        log.warn("Container is read-only; write to execution instead");
    } else throw e;
}

Prevention

When it happens

Trigger: Code holding the BpmnErrorVariableContainer built during error propagation (e.g. inside an event handler / error variable mapping that receives this container as a VariableScope) calls setVariable(name, value).

Common situations: Custom error/variable mapping code or listeners that attempt to persist variables while handling a caught BpmnError; reused generic variable-writing helper invoked in the error context; assuming the container behaves like an ExecutionEntity.

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

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ErrorPropagation.java:648

        @Override
        public Object getVariable(String variableName) {
            if (ERROR_CODE_VARIABLE_NAME.equals(variableName)) {
                return errorCode;
            } else if (ERROR_VARIABLE_NAME.equals(variableName)) {
                return error;
            } else if (ERROR_MESSAGE_VARIABLE_NAME.equals(variableName)) {
                return error != null ? error.getMessage() : null;
            } else if (additionalDataContainer != null) {
                return additionalDataContainer.getVariable(variableName);
            }

            return null;
        }

        @Override
        public void setVariable(String variableName, Object variableValue) {
            throw new UnsupportedOperationException("Not allowed to set variables in a bpmn error variable container");
        }

        @Override
        public void setTransientVariable(String variableName, Object variableValue) {
            throw new UnsupportedOperationException("Not allowed to set variables in a bpmn error variable container");
        }

        @Override
        public String getTenantId() {
            return tenantId;
        }

        @Override
        public Set<String> getVariableNames() {
            if (additionalDataContainer == null) {
                return Set.of(ERROR_CODE_VARIABLE_NAME, ERROR_VARIABLE_NAME, ERROR_MESSAGE_VARIABLE_NAME);
            }

View on GitHub (pinned to d6d39ce1c6)