flowable/flowable-engine · error · FlowableException

lazy loading outside command context for

Error message

lazy loading outside command context for 

What it means

VariableScopeImpl lazily loads its variable instances on first access, which requires an active Flowable command context because it queries the persistence layer. When variables are accessed outside a command (e.g. after the command context closed, or on a detached/async thread), ensureVariableInstancesInitialized throws FlowableException 'lazy loading outside command context for <scope>'.

Source

Thrown at modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/VariableScopeImpl.java:76

    protected Map<String, VariableInstance> transientVariables;

    protected ELContext cachedElContext;

    protected abstract Collection<VariableInstanceEntity> loadVariableInstances();

    protected abstract VariableScopeImpl getParentVariableScope();

    protected abstract void initializeVariableInstanceBackPointer(VariableInstance variableInstance);
    
    protected abstract void addLoggingSessionInfo(ObjectNode loggingNode);

    protected void ensureVariableInstancesInitialized() {
        if (variableInstances == null) {
            variableInstances = new HashMap<>();

            CommandContext commandContext = Context.getCommandContext();
            if (commandContext == null) {
                throw new FlowableException("lazy loading outside command context for " + this);
            }
            Collection<VariableInstanceEntity> variableInstancesList = loadVariableInstances();
            for (VariableInstanceEntity variableInstance : variableInstancesList) {
                variableInstances.put(variableInstance.getName(), variableInstance);
            }
        }
    }

    /**
     * Only to be used when creating a new entity, to avoid an extra call to the database.
     */
    public void internalSetVariableInstances(Map<String, VariableInstanceEntity> variableInstances) {
        this.variableInstances = variableInstances;
    }

    @Override
    public Map<String, Object> getVariables() {
        return collectVariables(new HashMap<>());

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Access variables inside the same command/transaction that loaded the execution (e.g. within the delegate or listener)
  2. Wrap external access in a command: managementService.executeCommand(ctx -> execution.getVariables()) and re-fetch the entity inside the command
  3. Re-load the execution entity inside a new command instead of using a stale/detached reference
  4. Avoid storing ExecutionEntity/TaskEntity references across transactions; store IDs and reload on demand

Example fix

// before
ExecutionEntity exec = ...; // captured earlier, outside command
Map<String,Object> vars = exec.getVariables(); // throws
// after
managementService.executeCommand(commandContext -> {
    ExecutionEntity exec = CommandContextUtil.getExecutionEntityManager(commandContext)
        .findById(executionId);
    return exec.getVariables();
});
Defensive patterns

Strategy: try-catch

Validate before calling

if (org.flowable.common.engine.impl.context.Context.getCommandContext() == null) {
    throw new IllegalStateException("variable access requires an active command context; wrap in executeCommand");
}

Try / catch

try {
    return execution.getVariables();
} catch (org.flowable.common.engine.api.FlowableException e) {
    if (e.getMessage().startsWith("lazy loading outside command context")) {
        return managementService.executeCommand(ctx ->
            executionEntityManager.findById(executionId).getVariables());
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling collectVariables, collectVariableInstances, getVariableInstance(Local), hasVariables(Local), or any getVariable call on a VariableScopeImpl (e.g. a detached ExecutionEntity) when Context.getCommandContext() returns null — after the command finished, in a different thread, or outside Flowable's command interceptor chain.

Common situations: Accessing execution/task variables after processEngine command completed; using execution objects from async threads; caching entities across command boundaries; calling variable APIs in non-command threads without wrapping in managementService.executeCommand.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/249afa91eb52e5b4. Report an issue: GitHub.