{"record":{"id":"249afa91eb52e5b4","repo":"flowable/flowable-engine","slug":"lazy-loading-outside-command-context-for-249afa","errorCode":null,"errorMessage":"lazy loading outside command context for ","messagePattern":"lazy loading outside command context for ","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/VariableScopeImpl.java","lineNumber":76,"sourceCode":"    protected Map<String, VariableInstance> transientVariables;\n\n    protected ELContext cachedElContext;\n\n    protected abstract Collection<VariableInstanceEntity> loadVariableInstances();\n\n    protected abstract VariableScopeImpl getParentVariableScope();\n\n    protected abstract void initializeVariableInstanceBackPointer(VariableInstance variableInstance);\n    \n    protected abstract void addLoggingSessionInfo(ObjectNode loggingNode);\n\n    protected void ensureVariableInstancesInitialized() {\n        if (variableInstances == null) {\n            variableInstances = new HashMap<>();\n\n            CommandContext commandContext = Context.getCommandContext();\n            if (commandContext == null) {\n                throw new FlowableException(\"lazy loading outside command context for \" + this);\n            }\n            Collection<VariableInstanceEntity> variableInstancesList = loadVariableInstances();\n            for (VariableInstanceEntity variableInstance : variableInstancesList) {\n                variableInstances.put(variableInstance.getName(), variableInstance);\n            }\n        }\n    }\n\n    /**\n     * Only to be used when creating a new entity, to avoid an extra call to the database.\n     */\n    public void internalSetVariableInstances(Map<String, VariableInstanceEntity> variableInstances) {\n        this.variableInstances = variableInstances;\n    }\n\n    @Override\n    public Map<String, Object> getVariables() {\n        return collectVariables(new HashMap<>());","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/VariableScopeImpl.java#L58-L94","documentation":"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>'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Access variables inside the same command/transaction that loaded the execution (e.g. within the delegate or listener)","Wrap external access in a command: managementService.executeCommand(ctx -> execution.getVariables()) and re-fetch the entity inside the command","Re-load the execution entity inside a new command instead of using a stale/detached reference","Avoid storing ExecutionEntity/TaskEntity references across transactions; store IDs and reload on demand"],"exampleFix":"// before\nExecutionEntity exec = ...; // captured earlier, outside command\nMap<String,Object> vars = exec.getVariables(); // throws\n// after\nmanagementService.executeCommand(commandContext -> {\n    ExecutionEntity exec = CommandContextUtil.getExecutionEntityManager(commandContext)\n        .findById(executionId);\n    return exec.getVariables();\n});","handlingStrategy":"try-catch","validationCode":"if (org.flowable.common.engine.impl.context.Context.getCommandContext() == null) {\n    throw new IllegalStateException(\"variable access requires an active command context; wrap in executeCommand\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return execution.getVariables();\n} catch (org.flowable.common.engine.api.FlowableException e) {\n    if (e.getMessage().startsWith(\"lazy loading outside command context\")) {\n        return managementService.executeCommand(ctx ->\n            executionEntityManager.findById(executionId).getVariables());\n    }\n    throw e;\n}","preventionTips":["Never cache ExecutionEntity/TaskEntity references across commands — store IDs and reload","Access variables within delegates/listeners or a managementService.executeCommand block","Avoid touching variables from async threads outside the command interceptor chain"],"tags":["java","flowable","lazy-loading","command-context"],"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"}