flowable/flowable-engine · error · UnsupportedOperationException

Empty object, no variables can be set

Error message

Empty object, no variables can be set

What it means

EmptyVariableScope is an immutable no-op VariableScope placeholder (e.g. used for executions/tasks that no longer exist or as a null-scope stand-in in delegate expression evaluation). Every mutating method deliberately throws UnsupportedOperationException because an empty scope can never hold variables. Throwing here is the library's contract that mutation on this object is a programming error.

Solutions

  1. Verify the scope you hold is a real, still-active execution/task before mutating: check the scope type or re-fetch the execution via runtimeService.
  2. Move variable writes earlier in the lifecycle (before process instance end / completion) inside the actual delegate execution.
  3. Guard mutation with an instanceof/type check for EmptyVariableScope and skip or log instead of mutating.
  4. If you intentionally need a throwaway scope, use a custom VariableScope implementation instead of the empty sentinel.

Example fix

// before
scope.setVariable("status", "done");

// after
if (scope instanceof EmptyVariableScope) {
    logger.warn("Skipping variable write: scope is empty/detached");
} else {
    scope.setVariable("status", "done");
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (scope == null || scope instanceof EmptyVariableScope) {
    throw new IllegalStateException("Scope is not writable");
}

Type guard

boolean isWritableScope(VariableScope scope) {
    return scope != null && !(scope instanceof EmptyVariableScope);
}

Try / catch

try {
    scope.setVariable("status", value);
} catch (UnsupportedOperationException e) {
    if (e.getMessage() != null && e.getMessage().contains("Empty object")) {
        logger.warn("Variable write skipped: scope is empty/detached");
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling setVariable(String, Object) on an EmptyVariableScope instance, typically obtained when the delegate/execution resolves to the EMPTY sentinel scope instead of a real ExecutionEntity/TaskEntity.

Common situations: Delegate code (JavaDelegate/TaskListener) calling execution.setVariable(...) when the execution was replaced by EmptyVariableScope (e.g. after process instance end or in history/simulation contexts); passing EmptyVariableScope into helper code expecting a writable scope.

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

Appendix: source

Thrown at modules/flowable-variable-service-api/src/main/java/org/flowable/variable/api/delegate/EmptyVariableScope.java:152

    @Override
    public VariableInstance getVariableInstance(String variableName, boolean fetchAllVariables) {
        return null;
    }

    @Override
    public VariableInstance getVariableInstanceLocal(String variableName) {
        return null;
    }

    @Override
    public VariableInstance getVariableInstanceLocal(String variableName, boolean fetchAllVariables) {
        return null;
    }

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

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

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

    @Override
    public Object setVariableLocal(String variableName, Object value, boolean fetchAllVariables) {
        throw new UnsupportedOperationException("Empty object, no variables can be set");
    }

    @Override

View on GitHub (pinned to d6d39ce1c6)