apache/dolphinscheduler · error · IllegalArgumentException
"The task relation from " + preTask.getName() + " to " + pos
Error message
"The task relation from " + preTask.getName() + " to " + postTask.getName() + " is already exists"
What it means
addTaskEdge rejects duplicate relations: after looking up both tasks, if the post task's predecessor list already contains the pre task's name, the same edge is being added twice, so it throws this IllegalArgumentException. Duplicate edges would double-count dependencies during DAG traversal.
Source
Thrown at dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/graph/WorkflowGraph.java:138
}
private void addTaskEdge(List<WorkflowTaskRelation> workflowTaskRelations) {
for (WorkflowTaskRelation workflowTaskRelation : workflowTaskRelations) {
long pre = workflowTaskRelation.getPreTaskCode();
long post = workflowTaskRelation.getPostTaskCode();
if (pre > 0 && post > 0) {
if (!taskDefinitionCodeMap.containsKey(pre)) {
throw new IllegalArgumentException("Cannot find task: " + pre);
}
if (!taskDefinitionCodeMap.containsKey(post)) {
throw new IllegalArgumentException("Cannot find task: " + post);
}
TaskDefinition preTask = checkNotNull(taskDefinitionCodeMap.get(pre), "Cannot find task: " + pre);
TaskDefinition postTask = checkNotNull(taskDefinitionCodeMap.get(post), "Cannot find task: " + pre);
List<String> predecessorsTasks = predecessors.get(postTask.getName());
if (predecessorsTasks.contains(preTask.getName())) {
throw new IllegalArgumentException("The task relation from " + preTask.getName() + " to "
+ postTask.getName() + " is already exists");
}
predecessorsTasks.add(preTask.getName());
List<String> successTasks = successors.get(preTask.getName());
if (successTasks.contains(postTask.getName())) {
throw new IllegalArgumentException("The task relation from " + preTask.getName() + " to "
+ postTask.getName() + " is already exists");
}
successTasks.add(postTask.getName());
}
if (pre <= 0 && post <= 0) {
throw new IllegalArgumentException("The task relation from " + pre + " to " + post + " is invalid");
}
}
}View on GitHub (pinned to 02eac45a1b)
Solutions
- Deduplicate the relations by (preTaskCode, postTaskCode) before constructing the graph
- Check t_ds_workflow_task_relation for duplicate (pre_task_code, post_task_code) rows and remove extras
- Add a unique constraint on (workflow_definition_code, pre_task_code, post_task_code) to prevent recurrence
- If parsing relations from JSON, use a Set keyed on the code pair during deserialization
Example fix
// before
new WorkflowGraph(tasks, relations); // (100 -> 200) appears twice
// after
Set<String> seen = new HashSet<>();
List<WorkflowTaskRelation> distinct = relations.stream()
.filter(r -> seen.add(r.getPreTaskCode() + "->" + r.getPostTaskCode()))
.collect(Collectors.toList());
WorkflowGraph g = new WorkflowGraph(tasks, distinct); Defensive patterns
Strategy: validation
Validate before calling
Set<String> seen = new HashSet<>();
for (WorkflowTaskRelation r : relations) {
String key = r.getPreTaskCode() + "->" + r.getPostTaskCode();
if (!seen.add(key)) throw new IllegalStateException("Duplicate relation: " + key);
} Try / catch
try {
WorkflowGraph graph = new WorkflowGraph(taskDefinitions, relations);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("is already exists")) log.error("Duplicate edge in workflow: {}", e.getMessage());
throw e;
} Prevention
- Use a Set/unique key when collecting relations from any source
- Add a unique DB constraint on (workflow, pre_task_code, post_task_code)
- Guard import/retry logic against re-inserting relation rows
- Deduplicate relations loaded via joins that can fan out rows
When it happens
Trigger: Constructing WorkflowGraph with t_ds_workflow_task_relation rows (or an in-memory relation list) containing the same (preTaskCode, postTaskCode) pair more than once.
Common situations: Duplicated relation rows created by a failed/retried save or import; re-running an import without deduplication; joining relations to task definitions in SQL producing duplicate rows.
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
- "The task relation from " + pre + " to " + post + " is inval
- 50032
- 50019
- WORKFLOW_NODE_HAS_CYCLE
- serious error: graph has cycle !
AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06).
Data as JSON: /api/errors/e37d59794ea15b9c.
Report an issue: GitHub.