{"record":{"id":"cf7396f866b3b813","repo":"flowable/flowable-engine","slug":"invalid-sub-process-identifier-identifier-already","errorCode":null,"errorMessage":"Invalid sub-process identifier: identifier already exists in host process definition","messagePattern":"Invalid sub-process identifier: identifier already exists in host process definition","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/dynamic/DynamicSubProcessJoinInjectUtil.java","lineNumber":60,"sourceCode":"import org.flowable.task.service.impl.persistence.entity.TaskEntity;\r\n\r\n/**\r\n * @author Tijs Rademakers\r\n */\r\npublic class DynamicSubProcessJoinInjectUtil extends BaseDynamicSubProcessInjectUtil {\r\n    \r\n    public static void injectSubProcessWithJoin(String taskId, Process process, BpmnModel bpmnModel, DynamicEmbeddedSubProcessBuilder dynamicEmbeddedSubProcessBuilder,\r\n                    ProcessDefinitionEntity originalProcessDefinitionEntity, DeploymentEntity newDeploymentEntity, CommandContext commandContext) {\r\n        \r\n        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);\r\n        TaskEntity taskEntity = processEngineConfiguration.getTaskServiceConfiguration().getTaskService().getTask(taskId);\r\n        FlowElement taskFlowElement = process.getFlowElement(taskEntity.getTaskDefinitionKey(), true);\r\n        if (!(taskFlowElement instanceof UserTask userTask)) {\r\n            throw new FlowableException(\"No UserTask instance found for task definition key \" + taskEntity.getTaskDefinitionKey());\r\n        }\r\n\r\n        if (dynamicEmbeddedSubProcessBuilder.getId() != null && process.getFlowElement(dynamicEmbeddedSubProcessBuilder.getId(), true) != null) {\r\n            throw new FlowableIllegalArgumentException(\"Invalid sub-process identifier: identifier already exists in host process definition\");\r\n        }\r\n        \r\n        GraphicInfo elementGraphicInfo = bpmnModel.getGraphicInfo(userTask.getId());\r\n        \r\n        SubProcess parentSubProcess = new SubProcess();\r\n        String subProcessId = dynamicEmbeddedSubProcessBuilder.nextSubProcessId(process.getFlowElementMap());\r\n        parentSubProcess.setId(subProcessId);\r\n        parentSubProcess.setName(userTask.getName());\r\n        \r\n        for (SequenceFlow incomingFlow : userTask.getIncomingFlows()) {\r\n            incomingFlow.setTargetRef(parentSubProcess.getId());\r\n        }\r\n        parentSubProcess.setIncomingFlows(userTask.getIncomingFlows());\r\n        \r\n        for (SequenceFlow outgoingFlow : userTask.getOutgoingFlows()) {\r\n            outgoingFlow.setSourceRef(parentSubProcess.getId());\r\n        }\r\n        parentSubProcess.setOutgoingFlows(userTask.getOutgoingFlows());\r","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/dynamic/DynamicSubProcessJoinInjectUtil.java#L42-L78","documentation":"Thrown by DynamicSubProcessJoinInjectUtil.injectSubProcessWithJoin when the id given to the DynamicEmbeddedSubProcessBuilder already exists as a flow element in the host process definition. Injecting a SubProcess with a duplicate element id would corrupt the BPMN model and activity lookup (ids must be unique within a process), so the engine rejects it with FlowableIllegalArgumentException.","triggerScenarios":"Calling injectSubProcessWithJoin after building a DynamicEmbeddedSubProcessBuilder whose explicit id (or a generated one from nextSubProcessId colliding with existing ids) duplicates an existing flow element id in the host process.","commonSituations":"Hard-coding a subprocess id like 'subProcess1' that already exists in the BPMN; re-running dynamic injection on a model where a previous injection already added an element with the same id.","solutions":["Choose a unique, non-existent id for the DynamicEmbeddedSubProcessBuilder, e.g. a UUID-based or prefixed name","Check process.getFlowElement(candidateId, true) == null before building the injection","Remove or migrate out previous injections if re-injection duplicated ids","Let the builder generate an id via nextSubProcessId instead of setting one that already exists"],"exampleFix":"// before\nbuilder.id(\"subProcess1\"); // already exists in host process\n// after\nString id = \"dynamicSubProcess-\" + UUID.randomUUID();\nif (process.getFlowElement(id, true) == null) builder.id(id);","handlingStrategy":"validation","validationCode":"if (dynamicEmbeddedSubProcessBuilder.getId() != null\n    && process.getFlowElement(dynamicEmbeddedSubProcessBuilder.getId(), true) != null) {\n    throw new IllegalArgumentException(\"Sub process id already exists in host process\");\n}","typeGuard":"static boolean isUniqueFlowElementId(Process process, String id) {\n    return id == null || process.getFlowElement(id, true) == null;\n}","tryCatchPattern":"try {\n    injectSubProcessWithJoin(taskId, builder, process, bpmnModel, def, deployment, ctx);\n} catch (FlowableIllegalArgumentException ex) {\n    if (ex.getMessage().contains(\"identifier already exists\")) {\n        // regenerate id and retry\n    } else throw ex;\n}","preventionTips":["Generate subprocess ids with a unique prefix/UUID instead of fixed names","Check getFlowElement(id) before setting the builder id","Avoid re-injecting the same id into an already-modified model","Keep an id registry for dynamically added elements per process definition"],"tags":["dynamic-bpmn","duplicate-id","subprocess-injection","flowable"],"backgroundTag":"invalid-identifier","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}