flowable/flowable-engine · error · FlowableException
A delegated ${taskEntity} cannot be completed, but should be
Error message
A delegated ${taskEntity} cannot be completed, but should be resolved instead. What it means
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.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TaskHelper.java:74
import org.flowable.task.service.impl.persistence.CountingTaskEntity;
import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.variable.service.event.impl.FlowableVariableEventBuilder;
import org.flowable.variable.service.impl.persistence.entity.VariableInstanceEntity;
import tools.jackson.databind.node.ObjectNode;
/**
* @author Tijs Rademakers
* @author Joram Barrez
*/
public class TaskHelper {
public static void completeTask(TaskEntity taskEntity, String userId, Map<String, Object> variables, Map<String, Object> localVariables,
Map<String, Object> transientVariables, Map<String, Object> localTransientVariables, CommandContext commandContext) {
if (taskEntity.getDelegationState() != null && taskEntity.getDelegationState() == DelegationState.PENDING) {
throw new FlowableException("A delegated " + taskEntity + " cannot be completed, but should be resolved instead.");
}
if (localVariables != null && !localVariables.isEmpty()) {
taskEntity.setVariablesLocal(localVariables);
}
if (variables != null && !variables.isEmpty()) {
if (taskEntity.getExecutionId() != null) {
ExecutionEntity execution = CommandContextUtil.getExecutionEntityManager().findById(taskEntity.getExecutionId());
if (execution != null) {
execution.setVariables(variables);
}
} else {
taskEntity.setVariables(variables);
}
}View on GitHub (pinned to d6d39ce1c6)
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.
Example fix
// before
taskService.completeTask(taskId);
// after
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task.getDelegationState() == DelegationState.PENDING) {
taskService.resolveTask(taskId, vars);
} else {
taskService.completeTask(taskId, vars);
} Defensive patterns
Strategy: validation
Validate before calling
Task t = taskService.createTaskQuery().taskId(taskId).singleResult(); boolean completable = t != null && t.getDelegationState() != DelegationState.PENDING; if (!completable) taskService.resolveTask(taskId, vars);
Type guard
boolean isDelegated(Task t) { return t != null && t.getDelegationState() == DelegationState.PENDING; } Try / catch
try { taskService.completeTask(taskId, vars); } catch (FlowableException e) { if (e.getMessage().contains("should be resolved")) taskService.resolveTask(taskId, vars); else throw e; } Prevention
- 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
When it happens
Trigger: Calling TaskService.completeTask(taskId) (TaskHelper.completeTask) on a task returned by TaskService.delegateTask(taskId, userId) while its DelegationState is still PENDING.
Common situations: 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.
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
- The ${task} cannot be deleted because is part of a running p
- The ${task} cannot be deleted because is part of a running c
- Cannot resume task with id '
- No task associated. Call businessProcess.startTask() first.
- taskId is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/6aa581a2fb9911c1.
Report an issue: GitHub.