{"record":{"id":"c8e5ea4a2afc3909","repo":"flowable/flowable-engine","slug":"a-delegated-task-cannot-be-completed-but-should-b","errorCode":null,"errorMessage":"A delegated task cannot be completed, but should be resolved instead.","messagePattern":"A delegated task cannot be completed, but should be resolved instead\\.","errorType":"exception","errorClass":"ActivitiException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/persistence/entity/TaskEntity.java","lineNumber":189,"sourceCode":"                    EngineConfigurationConstants.KEY_PROCESS_ENGINE_CONFIG);\n        }\n    }\n\n    /**\n     * Creates a new task. Embedded state and create time will be initialized. But this task still will have to be persisted. See {@link #insert(ExecutionEntity))}.\n     */\n    public static TaskEntity create(Date createTime) {\n        TaskEntity task = new TaskEntity();\n        task.isIdentityLinksInitialized = true;\n        task.createTime = createTime;\n        return task;\n    }\n\n    @SuppressWarnings(\"rawtypes\")\n    public void complete(Map variablesMap, boolean localScope, boolean fireEvents) {\n\n        if (getDelegationState() != null && getDelegationState() == DelegationState.PENDING) {\n            throw new ActivitiException(\"A delegated task cannot be completed, but should be resolved instead.\");\n        }\n\n        if (fireEvents) {\n            fireEvent(TaskListener.EVENTNAME_COMPLETE);\n        }\n\n        if (Authentication.getAuthenticatedUserId() != null && processInstanceId != null) {\n            getProcessInstance().involveUser(Authentication.getAuthenticatedUserId(), IdentityLinkType.PARTICIPANT);\n        }\n\n        if (Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled() && fireEvents) {\n            Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(\n                    ActivitiEventBuilder.createEntityWithVariablesEvent(FlowableEngineEventType.TASK_COMPLETED, this, variablesMap, localScope),\n                    EngineConfigurationConstants.KEY_PROCESS_ENGINE_CONFIG);\n        }\n\n        Context\n                .getCommandContext()","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/persistence/entity/TaskEntity.java#L171-L207","documentation":"TaskEntity.complete throws this when the task's delegationState is DelegationState.PENDING, i.e. the task was delegated to the assignee via TaskService.delegateTask and has not been resolved yet. A delegated task must go through TaskService.resolveTask, not complete, to preserve the delegation protocol. Completing it would silently discard the delegater's involvement.","triggerScenarios":"Calling taskService.complete(taskId) (or RuntimeData task completion paths that call TaskEntity.complete) on a task that is currently in PENDING delegation state after a prior delegateTask call.","commonSituations":"UI shows a 'complete' button for a delegated task; batch scripts completing all tasks assigned to a user without checking delegation state; task was delegated and the assignee tries to finish it instead of resolving it back.","solutions":["Call taskService.resolveTask(taskId) instead of complete() for delegated tasks","Check task.getDelegationState() == DelegationState.RESOLVED (or null) before completing in UI/service logic","If the delegation is no longer wanted, have the delegater resolve the task first, then complete it"],"exampleFix":"// before\nTask task = taskService.createTaskQuery().taskId(taskId).singleResult();\ntaskService.complete(taskId);\n// after\nTask task = taskService.createTaskQuery().taskId(taskId).singleResult();\nif (task.getDelegationState() == DelegationState.PENDING) {\n    taskService.resolveTask(taskId, vars);\n} else {\n    taskService.complete(taskId, vars);\n}","handlingStrategy":"validation","validationCode":"Task t = taskService.createTaskQuery().taskId(taskId).singleResult();\nboolean completable = t == null || t.getDelegationState() != DelegationState.PENDING;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check DelegationState before offering a complete action in the UI","For PENDING tasks always call resolveTask, then complete","Centralize task completion behind one service method that performs the state check"],"tags":["task","delegation","state-machine","workflow"],"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"}