flowable/flowable-engine · error · FlowableException

No UserTask instance found for " + taskEntity

Error message

No UserTask instance found for " + taskEntity

What it means

InjectParallelUserTaskCmd.updateBpmnProcess() fetches the task by taskId, resolves its current flow element in the process model, and requires it to be a UserTask. If the resolved FlowElement is a different element type (service task, receive task, sub process, etc.) it throws FlowableException 'No UserTask instance found for <taskEntity>', because parallel user task injection is only valid at user task positions.

Solutions

  1. Verify the current flow element for the task's taskDefinitionKey is a UserTask before invoking the injection API.
  2. Pick a task id for an actual user task (query taskService.createTaskQuery().taskCandidateGroup... etc.) rather than an arbitrary active execution.
  3. Re-deploy or correct the process definition if the task definition key mapping changed after a model update.
  4. Catch FlowableException and fall back to a different injection point.

Example fix

// before
processInstanceModification.injectParallelUserTask(nonUserTaskId, builder);
// after
TaskInfo task = taskService.createTaskQuery().taskId(taskId).singleResult();
FlowElement el = process.getFlowElement(task.getTaskDefinitionKey(), true);
if (el instanceof UserTask) {
    processInstanceModification.injectParallelUserTask(taskId, builder);
}
Defensive patterns

Strategy: validation

Validate before calling

FlowElement el = process.getFlowElement(task.getTaskDefinitionKey(), true);
if (!(el instanceof UserTask)) {
    throw new IllegalArgumentException("Injection point is not a UserTask: " + task.getTaskDefinitionKey());
}

Type guard

boolean isUserTaskElement(FlowElement el) { return el instanceof UserTask; }

Try / catch

try {
    modificationBuilder.injectParallelUserTask(taskId, builder);
} catch (FlowableException e) {
    if (e.getMessage().startsWith("No UserTask instance found")) {
        log.warn("Cannot inject parallel user task at non-user-task element for task {}", taskId);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling the dynamic injection API (DynamicBpmnService / process instance modification) with a taskId whose underlying taskDefinitionKey resolves to a non-UserTask flow element in the deployed BpmnModel.

Common situations: Injecting after the process definition changed so the task definition key now maps to a different element; passing an id of a task that is actually inside a service task loop; assuming the active element at any execution point is a user task.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/InjectParallelUserTaskCmd.java:69

        this.dynamicUserTaskBuilder = dynamicUserTaskBuilder;
    }

    @Override
    public Void execute(CommandContext commandContext) {
        createDerivedProcessDefinitionForTask(commandContext, taskId);
        return null;
    }

    @Override
    protected void updateBpmnProcess(CommandContext commandContext, Process process,
            BpmnModel bpmnModel, ProcessDefinitionEntity originalProcessDefinitionEntity, DeploymentEntity newDeploymentEntity) {
        
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        TaskEntity taskEntity = processEngineConfiguration.getTaskServiceConfiguration().getTaskService().getTask(taskId);
        FlowElement flowElement = process.getFlowElement(taskEntity.getTaskDefinitionKey(), true);
        if (!(flowElement instanceof UserTask userTask)) {
            throw new FlowableException("No UserTask instance found for " + taskEntity);
        }

        SubProcess subProcess = new SubProcess();
        String subProcessId = dynamicUserTaskBuilder.nextSubProcessId(process.getFlowElementMap());
        subProcess.setId(subProcessId);
        subProcess.setName(flowElement.getName());
        
        for (SequenceFlow incomingFlow : userTask.getIncomingFlows()) {
            incomingFlow.setTargetRef(subProcess.getId());
        }
        subProcess.setIncomingFlows(userTask.getIncomingFlows());
        
        for (SequenceFlow outgoingFlow : userTask.getOutgoingFlows()) {
            outgoingFlow.setSourceRef(subProcess.getId());
        }
        subProcess.setOutgoingFlows(userTask.getOutgoingFlows());
        
        userTask.setIncomingFlows(new ArrayList<>());

View on GitHub (pinned to d6d39ce1c6)