flowable/flowable-engine · error · UnsupportedOperationException

Empty object, no variables can be set

Error message

Empty object, no variables can be set

What it means

EmptyVariableContainer is a read-only, immutable variable scope that always returns null for getVariable; its setVariable/setTransientVariable deliberately throw UnsupportedOperationException("Empty object, no variables can be set") because the container represents an empty scope and cannot store any variables.

Solutions

  1. Write variables to a real, mutable scope (DelegateExecution, DelegateTask, VariableScope from the execution context) instead of the empty container
  2. Check whether the container is an EmptyVariableContainer (or check writability) before writing
  3. If you only need reads, keep in mind getVariable always returns null — obtain actual variables from the execution instead

Example fix

// before
VariableScope scope = resolveScope();
scope.setVariable("approved", true); // throws if EmptyVariableContainer
// after
VariableScope scope = resolveScope();
if (scope instanceof EmptyVariableContainer) {
    throw new IllegalStateException("Cannot write variables to empty scope");
}
scope.setVariable("approved", true);
Defensive patterns

Strategy: type-guard

Validate before calling

// ensure the scope is writable before setting variables
if (scope instanceof EmptyVariableContainer) {
    throw new IllegalStateException("Scope is read-only (empty); cannot set variables");
}

Type guard

static boolean isWritableScope(VariableScope scope) {
    return !(scope instanceof EmptyVariableContainer);
}

Try / catch

try {
    scope.setVariable("approved", true);
} catch (UnsupportedOperationException e) {
    LOGGER.error("Attempted to write variables to an empty variable container");
    throw new IllegalStateException("Use a real DelegateExecution/Task scope for writes", e);
}

Prevention

When it happens

Trigger: Calling setVariable(name, value) or setTransientVariable(name, value) on an EmptyVariableContainer instance — e.g. code obtained a variable scope that is the empty container and then attempts to write.

Common situations: Delegate/listener code writing variables to a scope resolved in a context with no variables (such as certain delegate-execution placeholders), or tests using EmptyVariableContainer and then attempting writes.

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

Appendix: source

Thrown at modules/flowable-engine-common-api/src/main/java/org/flowable/common/engine/api/variable/EmptyVariableContainer.java:37

 * @author Arthur Hupka-Merle
 */
class EmptyVariableContainer implements VariableContainer {

    static final EmptyVariableContainer INSTANCE = new EmptyVariableContainer();

    @Override
    public boolean hasVariable(String variableName) {
        return false;
    }

    @Override
    public Object getVariable(String variableName) {
        return null;
    }

    @Override
    public void setVariable(String variableName, Object variableValue) {
        throw new UnsupportedOperationException("Empty object, no variables can be set");
    }

    @Override
    public void setTransientVariable(String variableName, Object variableValue) {
        throw new UnsupportedOperationException("Empty object, no variables can be set");
    }

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

    @Override
    public Set<String> getVariableNames() {
        return Collections.emptySet();
    }
}

View on GitHub (pinned to d6d39ce1c6)