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
- Write variables on the DelegateExecution / process execution instead of the error variable container
- Read-only usage: only call getter methods (getVariable, getTenantId) on this container
- Capture values into the error event's variable mappings defined in the BPMN (in/out mappings) rather than calling setVariable
- 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
- Never treat BpmnErrorVariableContainer as writable; it is a read-only view
- Move variable writes into BPMN in/out mappings or the parent execution
- Review generic variable-copy utilities for scope-blind writes
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
- Empty object, no variables can be set
- Couldn't deserialize object in variable
- couldn't find a variable type that is able to serialize
- Couldn't serialize value '' in variable ''
- Couldn't serialize value
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)