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

  1. Deduplicate the relations by (preTaskCode, postTaskCode) before constructing the graph
  2. Check t_ds_workflow_task_relation for duplicate (pre_task_code, post_task_code) rows and remove extras
  3. Add a unique constraint on (workflow_definition_code, pre_task_code, post_task_code) to prevent recurrence
  4. 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

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


AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06). Data as JSON: /api/errors/e37d59794ea15b9c. Report an issue: GitHub.