{"record":{"id":"ce12e1f798278914","repo":"flowable/flowable-engine","slug":"lazy-loading-outside-command-context-for-this","errorCode":null,"errorMessage":"lazy loading outside command context for \" + this","messagePattern":"lazy loading outside command context for \" \\+ this","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/ExecutionEntityImpl.java","lineNumber":945,"sourceCode":"        // Record historic variable deletion\n        CommandContextUtil.getHistoryManager().recordVariableRemoved(variableInstance);\n\n        // Record historic detail\n        CommandContextUtil.getHistoryManager().recordHistoricDetailVariableCreate(variableInstance, this, true,\n            getRelatedActivityInstanceId(this), clock.getCurrentTime());\n    }\n    \n    @Override\n    protected boolean isPropagateToHistoricVariable() {\n        return false;\n    }\n\n    @Override\n    protected VariableInstanceEntity getSpecificVariable(String variableName) {\n\n        CommandContext commandContext = Context.getCommandContext();\n        if (commandContext == null) {\n            throw new FlowableException(\"lazy loading outside command context for \" + this);\n        }\n\n        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);\n        return processEngineConfiguration.getVariableServiceConfiguration().getVariableService()\n                .createInternalVariableInstanceQuery()\n                .executionId(id)\n                .withoutTaskId()\n                .name(variableName)\n                .singleResult();\n    }\n\n    @Override\n    protected List<VariableInstanceEntity> getSpecificVariables(Collection<String> variableNames) {\n        CommandContext commandContext = Context.getCommandContext();\n        if (commandContext == null) {\n            throw new FlowableException(\"lazy loading outside command context for \" + this);\n        }\n","sourceCodeStart":927,"sourceCodeEnd":963,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/ExecutionEntityImpl.java#L927-L963","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (outside command context)\nExecutionEntity execution = ...; // captured earlier\nString value = (String) execution.getVariable(\"key\"); // lazy load -> throws\n// after (inside command)\nString value = managementService.executeCommand(commandContext ->\n    CommandContextUtil.getExecutionEntityManager(commandContext)\n        .findById(executionId).getVariable(\"key\"));","handlingStrategy":"type-guard","validationCode":"// Java: ensure command context exists before lazy variable access\nimport org.flowable.common.engine.impl.interceptor.CommandContextUtil;\nboolean inCommandContext() {\n    return Context.getCommandContext() != null;\n}","typeGuard":"boolean canLazyLoad(ExecutionEntity e) {\n    return Context.getCommandContext() != null && e.getId() != null;\n}","tryCatchPattern":"try {\n    Object v = execution.getVariable(\"key\");\n} catch (FlowableException e) {\n    if (e.getMessage().startsWith(\"lazy loading outside command context\")) {\n        // re-fetch inside a command: managementService.executeCommand(...)\n    } else { throw e; }\n}","preventionTips":["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."],"tags":["lazy-loading","command-context","flowable","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}