flowable/flowable-engine · error · FlowableException
lazy loading outside command context for " + this
Error message
lazy loading outside command context for " + this
What it means
ExecutionEntityImpl lazily loads variables on demand, but this requires an active command (transaction) context. getSpecificVariable throws this FlowableException when Context.getCommandContext() returns null, i.e. variable access happens outside any engine command, such as after the transaction/context closed.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/ExecutionEntityImpl.java:945
// Record historic variable deletion
CommandContextUtil.getHistoryManager().recordVariableRemoved(variableInstance);
// Record historic detail
CommandContextUtil.getHistoryManager().recordHistoricDetailVariableCreate(variableInstance, this, true,
getRelatedActivityInstanceId(this), clock.getCurrentTime());
}
@Override
protected boolean isPropagateToHistoricVariable() {
return false;
}
@Override
protected VariableInstanceEntity getSpecificVariable(String variableName) {
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);
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Read all needed variable values inside the command/command-context scope (e.g. within the delegate or a ProcessEngine-configured Command) and store plain values, not entities.
- Use an engine command to wrap access: managementService.executeCommand(cmd -> ...) and fetch variables there.
- Re-fetch variables through the runtime service API (runtimeService.getVariable(executionId, name)) instead of using the detached entity.
- If async access is needed, pass extracted variable values (copies) to the async code.
Example fix
// before (outside command context)
ExecutionEntity execution = ...; // captured earlier
String value = (String) execution.getVariable("key"); // lazy load -> throws
// after (inside command)
String value = managementService.executeCommand(commandContext ->
CommandContextUtil.getExecutionEntityManager(commandContext)
.findById(executionId).getVariable("key")); Defensive patterns
Strategy: type-guard
Validate before calling
// Java: ensure command context exists before lazy variable access
import org.flowable.common.engine.impl.interceptor.CommandContextUtil;
boolean inCommandContext() {
return Context.getCommandContext() != null;
} Type guard
boolean canLazyLoad(ExecutionEntity e) {
return Context.getCommandContext() != null && e.getId() != null;
} Try / catch
try {
Object v = execution.getVariable("key");
} catch (FlowableException e) {
if (e.getMessage().startsWith("lazy loading outside command context")) {
// re-fetch inside a command: managementService.executeCommand(...)
} else { throw e; }
} Prevention
- Never keep ExecutionEntity/TaskEntity references beyond the engine API call.
- Wrap off-command access in managementService.executeCommand.
- Extract variable values into plain objects before going async or leaving a delegate.
- Prefer RuntimeService.getVariable(executionId, name) over detached entity access.
When it happens
Trigger: Accessing variables on an ExecutionEntity outside the engine's command context — e.g. holding a reference to an execution entity in a delegate and reading variables after command completion, using entities in async threads, or touching detached/hydrated entities in application code after the engine API call returned.
Common situations: Caching ExecutionEntity instances across requests; spawning threads in delegates that read execution variables later; accessing lazy fields inside afterCommit callbacks or JTA Synchronization; returning entities from a service method and dereferencing variables in the view layer.
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
- lazy loading outside command context for
- lazy loading outside command context for
- lazy loading outside command context for
- lazy loading outside command context
- lazy loading outside command context
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/ce12e1f798278914.
Report an issue: GitHub.