flowable/flowable-engine · error · FlowableException

lazy loading outside command context for

Error message

lazy loading outside command context for 

What it means

ExecutionEntityImpl.getSpecificVariables lazy-loads a subset of an execution's variables on demand. Lazy loading only works inside a Flowable command context, because it needs the command context to reach the VariableService and run a query. When the entity is accessed outside a command (e.g. from a detached thread, a listener thread, or after the command finished), Context.getCommandContext() returns null and Flowable throws this FlowableException instead of returning partial data.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/ExecutionEntityImpl.java:961

        CommandContext commandContext = Context.getCommandContext();
        if (commandContext == null) {
            throw new FlowableException("lazy loading outside command context for " + this);
        }

        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        return processEngineConfiguration.getVariableServiceConfiguration().getVariableService()
                .createInternalVariableInstanceQuery()
                .executionId(id)
                .withoutTaskId()
                .name(variableName)
                .singleResult();
    }

    @Override
    protected List<VariableInstanceEntity> getSpecificVariables(Collection<String> variableNames) {
        CommandContext commandContext = Context.getCommandContext();
        if (commandContext == null) {
            throw new FlowableException("lazy loading outside command context for " + this);
        }

        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        return processEngineConfiguration.getVariableServiceConfiguration().getVariableService()
                .createInternalVariableInstanceQuery()
                .executionId(id)
                .withoutTaskId()
                .names(variableNames)
                .list();
    }

    // event subscription support //////////////////////////////////////////////

    @Override
    public List<EventSubscriptionEntity> getEventSubscriptions() {
        ensureEventSubscriptionsInitialized();
        return eventSubscriptions;
    }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Wrap the entity access in a command: managementService.executeCommand(new CommandCommandContext...) or run the logic inside a Flowable command/listener so a CommandContext is active.
  2. Load all needed variables while still inside the original command (e.g. in the JavaDelegate/TaskListener), pass values (not entities) to other threads.
  3. For Spring apps, use the flowable-spring integration (SpringProcessEngineConfiguration) which keeps a command context open for the transaction, or annotate with @Transactional plus Flowable's command context propagation.
  4. If async, re-fetch data via the public API (runtimeService.getVariables(executionId)) instead of touching the lazy entity.

Example fix

// before (async thread, entity passed from a command)
List<VariableInstanceEntity> vars = execution.getVariables();

// after (inside the same command, or re-query via public API)
Map<String, Object> vars = runtimeService.getVariables(execution.getId());
Defensive patterns

Strategy: validation

Validate before calling

if (Context.getCommandContext() == null) {
    // lazy loading unavailable: re-fetch via public API instead
    Map<String, Object> vars =
        runtimeService.getVariables(execution.getId());
}

Type guard

boolean isInsideCommand() {
    return Context.getCommandContext() != null;
}

Try / catch

try {
    vars = execution.getVariables();
} catch (FlowableException e) {
    if (e.getMessage().startsWith("lazy loading outside command context")) {
        vars = runtimeService.getVariables(execution.getId());
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling getVariables()/getVariable() on an ExecutionEntity (or TaskEntity, etc.) obtained from an async executor thread, a spring @Async method, a scheduled job, or a listener outside the command interceptor chain; holding a reference to an entity after CommandContext close and touching its variable collection later.

Common situations: Custom JobExecutors or thread pools using entities across threads; Spring integration where entity access happens outside a Flowable command (missing flowable spring command wrapper); unit tests constructing/inspecting entities directly without running a command.

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