apache/dolphinscheduler · error · ServiceException

50019

50019

Error message

workflow node has cycle

What it means

Thrown when the workflow DAG built from the task relations contains a cycle. DolphinScheduler workflows must be a directed acyclic graph; graphHasCycle detects dependency loops among the task nodes before persisting.

Source

Thrown at dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowDefinitionServiceImpl.java:420

                    .map(workflowTaskRelationLog -> JSONUtils.parseObject(
                            JSONUtils.toJsonString(workflowTaskRelationLog),
                            WorkflowTaskRelation.class))
                    .collect(Collectors.toList());
            List<TaskNode> taskNodeList = processService.transformTask(workflowTaskRelations, taskDefinitionLogs);
            if (taskNodeList.size() != taskRelationList.size()) {
                Set<Long> postTaskCodes = taskRelationList.stream().map(WorkflowTaskRelationLog::getPostTaskCode)
                        .collect(Collectors.toSet());
                Set<Long> taskNodeCodes = taskNodeList.stream().map(TaskNode::getCode).collect(Collectors.toSet());
                Collection<Long> codes = CollectionUtils.subtract(postTaskCodes, taskNodeCodes);
                if (CollectionUtils.isNotEmpty(codes)) {
                    String taskCodes = StringUtils.join(codes, Constants.COMMA);
                    log.error("Task definitions do not exist, taskCodes:{}.", taskCodes);
                    throw new ServiceException(Status.TASK_DEFINE_NOT_EXIST, taskCodes);
                }
            }
            if (graphHasCycle(taskNodeList)) {
                log.error("workflow DAG has cycle.");
                throw new ServiceException(Status.WORKFLOW_NODE_HAS_CYCLE);
            }

            // check whether the task relation json is normal
            for (WorkflowTaskRelationLog workflowTaskRelationLog : taskRelationList) {
                if (workflowTaskRelationLog.getPostTaskCode() == 0) {
                    log.error("The post_task_code or post_task_version of workflowTaskRelationLog can not be zero, " +
                            "workflowTaskRelationLogId:{}.", workflowTaskRelationLog.getId());
                    throw new ServiceException(Status.CHECK_WORKFLOW_TASK_RELATION_ERROR);
                }
            }
            return taskRelationList;
        } catch (ServiceException ex) {
            throw ex;
        } catch (Exception e) {
            log.error("Check task relation list error, meet an unknown exception, given taskRelationJson: {}",
                    taskRelationJson, e);
            throw new ServiceException(Status.REQUEST_PARAMS_NOT_VALID_ERROR);
        }

View on GitHub (pinned to 02eac45a1b)

Solutions

  1. Inspect the relation list and remove the edge(s) that close the loop
  2. Redraw dependencies in the UI designer, which prevents cyclic connections
  3. Topologically validate your relation JSON (e.g. with a Kahn's-algorithm script) before submitting

Example fix

// before
[{pre:A,post:B},{pre:B,post:A}] // cycle
// after
[{pre:A,post:B}]
Defensive patterns

Strategy: validation

Validate before calling

// Kahn's algorithm cycle check before submitting
Map<Long, List<Long>> adj = buildAdjacency(relations); Deque<Long> q = nodesWithZeroIndegree(adj);
int visited = 0; while (!q.isEmpty()) { Long n = q.poll(); visited++; for (Long m : adj.get(n)) if (--indeg(m) == 0) q.add(m); }
if (visited != nodeCount) throw new IllegalArgumentException("relation graph has a cycle");

Try / catch

try { ... } catch (ServiceException e) { if (e.getCode() == 50019) { /* redraw DAG without back edges */ } }

Prevention

When it happens

Trigger: updateWorkflowDefinition/importWorkflowDefinition where relations form a loop, e.g. task A's postTaskCode is B and B's postTaskCode is A, or a task depends on itself.

Common situations: Manually editing relation JSON and introducing a back edge; importing a workflow exported from another tool allowing cycles; merge conflicts in workflow JSON leaving both directions of a dependency.

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/b990aa350d66b5d4. Report an issue: GitHub.