flowable/flowable-engine · error · FlowableCdiException

Cannot resume task with id '

Error message

Cannot resume task with id '

What it means

startTask resolves a task id via TaskService and throws FlowableCdiException if no such task exists, refusing to resume/associate the conversation with that task. It only proceeds when a queryable, live task matches the id.

Source

Thrown at modules/flowable-cdi/src/main/java/org/flowable/cdi/BusinessProcess.java:330

    }

    // -------------------------------------

    /**
     * Associates the task with the provided taskId with the current conversation.
     *
     * @param taskId the id of the task
     * @return the resumed task
     * @throws FlowableCdiException if no such task is found
     */
    public Task startTask(String taskId) {
        Task currentTask = associationManager.getTask();
        if (currentTask != null && currentTask.getId().equals(taskId)) {
            return currentTask;
        }
        Task task = processEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new FlowableCdiException("Cannot resume task with id '" + taskId + "', no such task.");
        }
        associationManager.setTask(task);
        associateExecutionById(task.getProcessInstanceId());
        return task;
    }

    /**
     * @see #startTask(String)
     * <p>
     * this method allows to start a conversation if no conversation is active
     */
    public Task startTask(String taskId, boolean beginConversation) {
        if (beginConversation) {
            Conversation conversation = conversationInstance.get();
            if (conversation.isTransient()) {
                conversation.begin();
            }
        }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Check the task exists before starting: taskService.createTaskQuery().taskId(id).singleResult().
  2. Treat FlowableCdiException as 'task already completed/invalid' and redirect the user appropriately.
  3. Regenerate or reload the task id from a fresh query rather than caching it.

Example fix

// before
Task t = businessProcess.startTask(taskId); // throws if completed
// after
if (taskService.createTaskQuery().taskId(taskId).singleResult() != null) {
  Task t = businessProcess.startTask(taskId);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (taskService.createTaskQuery().taskId(taskId).singleResult() == null) {
  // task already completed or invalid
}

Type guard

boolean taskExists(String id) {
  return taskService.createTaskQuery().taskId(id).count() > 0;
}

Try / catch

try {
  businessProcess.startTask(taskId);
} catch (FlowableCdiException e) {
  // treat as task already completed; redirect user
}

Prevention

When it happens

Trigger: Calling businessProcess.startTask(taskId) / setTaskId / setTask with an id of a task that was completed, deleted, or never existed.

Common situations: Users completing the same task in two browser tabs; stale links to tasks from finished processes; tests reusing task ids after taskService.complete().

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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