{"record":{"id":"6aa581a2fb9911c1","repo":"flowable/flowable-engine","slug":"a-delegated-taskentity-cannot-be-completed-but","errorCode":null,"errorMessage":"A delegated ${taskEntity} cannot be completed, but should be resolved instead.","messagePattern":"A delegated (.+?) cannot be completed, but should be resolved instead\\.","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TaskHelper.java","lineNumber":74,"sourceCode":"import org.flowable.task.service.impl.persistence.CountingTaskEntity;\nimport org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity;\nimport org.flowable.task.service.impl.persistence.entity.TaskEntity;\nimport org.flowable.variable.service.event.impl.FlowableVariableEventBuilder;\nimport org.flowable.variable.service.impl.persistence.entity.VariableInstanceEntity;\n\nimport tools.jackson.databind.node.ObjectNode;\n\n/**\n * @author Tijs Rademakers\n * @author Joram Barrez\n */\npublic class TaskHelper {\n\n    public static void completeTask(TaskEntity taskEntity, String userId, Map<String, Object> variables, Map<String, Object> localVariables,\n            Map<String, Object> transientVariables, Map<String, Object> localTransientVariables, CommandContext commandContext) {\n\n        if (taskEntity.getDelegationState() != null && taskEntity.getDelegationState() == DelegationState.PENDING) {\n            throw new FlowableException(\"A delegated \" + taskEntity + \" cannot be completed, but should be resolved instead.\");\n        }\n\n        if (localVariables != null && !localVariables.isEmpty()) {\n            taskEntity.setVariablesLocal(localVariables);\n        }\n\n        if (variables != null && !variables.isEmpty()) {\n            if (taskEntity.getExecutionId() != null) {\n                ExecutionEntity execution = CommandContextUtil.getExecutionEntityManager().findById(taskEntity.getExecutionId());\n                if (execution != null) {\n                    execution.setVariables(variables);\n                }\n\n            } else {\n                taskEntity.setVariables(variables);\n\n            }\n        }","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TaskHelper.java#L56-L92","documentation":"Flowable throws this when completing a task whose delegation state is PENDING. A delegated task must be resolved (TaskService.resolveTask) so ownership returns to the delegator, not completed by the delegate. The engine refuses to complete to preserve delegation semantics.","triggerScenarios":"Calling TaskService.completeTask(taskId) (TaskHelper.completeTask) on a task returned by TaskService.delegateTask(taskId, userId) while its DelegationState is still PENDING.","commonSituations":"Developers treating delegated tasks like normal assignments in a UI; completing on behalf of a user who received the task via delegation; forgetting that delegation requires resolve, not complete.","solutions":["Call taskService.resolveTask(taskId, variables) instead of completeTask for delegated tasks.","Check task.getDelegationState() == DelegationState.PENDING before completing and branch to resolveTask.","If the task should not be delegated anymore, have the delegator resolve it back and then complete it.","If delegation was set by mistake, re-assign the task with taskService.setAssignee instead of delegating."],"exampleFix":"// before\ntaskService.completeTask(taskId);\n// after\nTask task = taskService.createTaskQuery().taskId(taskId).singleResult();\nif (task.getDelegationState() == DelegationState.PENDING) {\n    taskService.resolveTask(taskId, vars);\n} else {\n    taskService.completeTask(taskId, vars);\n}","handlingStrategy":"validation","validationCode":"Task t = taskService.createTaskQuery().taskId(taskId).singleResult();\nboolean completable = t != null && t.getDelegationState() != DelegationState.PENDING;\nif (!completable) taskService.resolveTask(taskId, vars);","typeGuard":"boolean isDelegated(Task t) { return t != null && t.getDelegationState() == DelegationState.PENDING; }","tryCatchPattern":"try { taskService.completeTask(taskId, vars); } catch (FlowableException e) { if (e.getMessage().contains(\"should be resolved\")) taskService.resolveTask(taskId, vars); else throw e; }","preventionTips":["Check DelegationState before any complete call","In UIs, render 'Resolve' instead of 'Complete' for PENDING-delegation tasks","Centralize task completion in one service method that handles delegation"],"tags":["flowable","task","delegation","invalid-state-transition"],"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"}