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

  1. Call taskService.resolveTask(taskId, variables) instead of completeTask for delegated tasks.
  2. Check task.getDelegationState() == DelegationState.PENDING before completing and branch to resolveTask.
  3. If the task should not be delegated anymore, have the delegator resolve it back and then complete it.
  4. 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

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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/6aa581a2fb9911c1. Report an issue: GitHub.