flowable/flowable-engine · error · FlowableException
No UserTask instance found for task definition key " +…
Error message
No UserTask instance found for task definition key " + taskEntity.getTaskDefinitionKey()
What it means
Thrown by DynamicSubProcessJoinInjectUtil.injectSubProcessWithJoin when dynamically injecting an embedded subprocess at a running task: the task identified by taskId does not resolve to a UserTask flow element in the process model. The injection algorithm anchors the new subprocess around a user task, so any other element type (service task, gateway, etc.) is rejected.
Solutions
- Pass the taskId of an active UserTask whose task definition key exists as a UserTask in the current process definition
- Verify process.getFlowElement(taskEntity.getTaskDefinitionKey(), true) resolves to a UserTask in the deployed BPMN
- Redeploy or reference the correct process definition if the model and runtime are out of sync
- Use an injection API suited to non-user-task anchors instead of the join-injection utility
Example fix
// before injectSubProcessWithJoin(serviceTaskTaskId, builder, ...); // service task, fails // after Task task = taskService.createTaskQuery().taskCandidateUser(user).singleResult(); // must be a UserTask injectSubProcessWithJoin(task.getId(), builder, ...);
Defensive patterns
Strategy: validation
Validate before calling
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
FlowElement el = process.getFlowElement(task.getTaskDefinitionKey(), true);
if (!(el instanceof UserTask)) throw new IllegalArgumentException("taskId must anchor on a UserTask"); Type guard
static boolean isUserTaskAnchor(Process process, TaskEntity task) {
return process.getFlowElement(task.getTaskDefinitionKey(), true) instanceof UserTask;
} Try / catch
try {
injectSubProcessWithJoin(taskId, builder, process, bpmnModel, def, deployment, commandContext);
} catch (FlowableException ex) {
if (ex.getMessage().startsWith("No UserTask instance found")) {
// pick a UserTask-anchored taskId
} else throw ex;
} Prevention
- Only invoke join-injection on tasks whose definition key is a UserTask in the model
- Re-resolve the process definition after any dynamic model change
- Avoid injecting at auto-completed or service tasks
- Assert task definition key presence in the deployed BPMN first
When it happens
Trigger: Calling DynamicBpmnService-style dynamic injection (injectSubProcessWithJoin) with a taskId whose task definition key points at a non-UserTask element, or a task definition key that is missing/stale in the process model (getFlowElement returns null or another FlowElement).
Common situations: Passing a standalone-task id that has no matching activity in the model; the process definition was changed so the task definition key no longer maps to the UserTask; injecting at an automatically executed task instead of a user task.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid sub-process identifier: identifier already exists…
- No multi instance execution found for activity id
- A channel key detection value is required for inbound…
- A channel key detection value is required for the channel…
- A datasource is required for initializing the engine
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/0eaaba0b51fa20ef.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/dynamic/DynamicSubProcessJoinInjectUtil.java:56
import org.flowable.engine.impl.persistence.entity.ResourceEntity;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
/**
* @author Tijs Rademakers
*/
public class DynamicSubProcessJoinInjectUtil extends BaseDynamicSubProcessInjectUtil {
public static void injectSubProcessWithJoin(String taskId, Process process, BpmnModel bpmnModel, DynamicEmbeddedSubProcessBuilder dynamicEmbeddedSubProcessBuilder,
ProcessDefinitionEntity originalProcessDefinitionEntity, DeploymentEntity newDeploymentEntity, CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
TaskEntity taskEntity = processEngineConfiguration.getTaskServiceConfiguration().getTaskService().getTask(taskId);
FlowElement taskFlowElement = process.getFlowElement(taskEntity.getTaskDefinitionKey(), true);
if (!(taskFlowElement instanceof UserTask userTask)) {
throw new FlowableException("No UserTask instance found for task definition key " + taskEntity.getTaskDefinitionKey());
}
if (dynamicEmbeddedSubProcessBuilder.getId() != null && process.getFlowElement(dynamicEmbeddedSubProcessBuilder.getId(), true) != null) {
throw new FlowableIllegalArgumentException("Invalid sub-process identifier: identifier already exists in host process definition");
}
GraphicInfo elementGraphicInfo = bpmnModel.getGraphicInfo(userTask.getId());
SubProcess parentSubProcess = new SubProcess();
String subProcessId = dynamicEmbeddedSubProcessBuilder.nextSubProcessId(process.getFlowElementMap());
parentSubProcess.setId(subProcessId);
parentSubProcess.setName(userTask.getName());
for (SequenceFlow incomingFlow : userTask.getIncomingFlows()) {
incomingFlow.setTargetRef(parentSubProcess.getId());
}
parentSubProcess.setIncomingFlows(userTask.getIncomingFlows());
View on GitHub (pinned to d6d39ce1c6)