{"record":{"id":"f04108f10de4e2c6","repo":"apache/dolphinscheduler","slug":"workflow-dag-is-empty","errorCode":"WORKFLOW_DAG_IS_EMPTY","errorMessage":"WORKFLOW_DAG_IS_EMPTY: workflow dag is empty","messagePattern":"WORKFLOW_DAG_IS_EMPTY: workflow dag is empty","errorType":"error_code","errorClass":"ServiceException","httpStatus":null,"severity":"error","filePath":"dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowDefinitionServiceImpl.java","lineNumber":949,"sourceCode":"     * @return check result code\n     */\n    @Override\n    public void checkWorkflowNodeList(String workflowTaskRelationJson,\n                                      List<TaskDefinitionLog> taskDefinitionLogsList) {\n        try {\n            if (workflowTaskRelationJson == null) {\n                log.error(\"workflow task relation data is null.\");\n                throw new ServiceException(Status.DATA_IS_NOT_VALID, \"null\");\n            }\n\n            List<WorkflowTaskRelation> taskRelationList =\n                    JSONUtils.toList(workflowTaskRelationJson, WorkflowTaskRelation.class);\n            // Check whether the task node is normal\n            List<TaskNode> taskNodes = processService.transformTask(taskRelationList, taskDefinitionLogsList);\n\n            if (CollectionUtils.isEmpty(taskNodes)) {\n                log.error(\"Task node data is empty.\");\n                throw new ServiceException(Status.WORKFLOW_DAG_IS_EMPTY);\n            }\n\n            // check has cycle\n            if (graphHasCycle(taskNodes)) {\n                log.error(\"workflow DAG has cycle.\");\n                throw new ServiceException(Status.WORKFLOW_NODE_HAS_CYCLE);\n            }\n\n            // check whether the workflow definition json is normal\n            for (TaskNode taskNode : taskNodes) {\n                if (!checkTaskParameters(taskNode.getType(), taskNode.getParams())) {\n                    throw new ServiceException(Status.WORKFLOW_NODE_S_PARAMETER_INVALID, taskNode.getName());\n                }\n\n                // check extra params\n                CheckUtils.checkOtherParams(taskNode.getExtras());\n            }\n        } catch (ServiceException e) {","sourceCodeStart":931,"sourceCodeEnd":967,"githubUrl":"https://github.com/apache/dolphinscheduler/blob/02eac45a1b6676e639fcbfb4be2243de5771b05d/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowDefinitionServiceImpl.java#L931-L967","documentation":"Thrown by checkWorkflowJsonValidation (WorkflowDefinitionServiceImpl) when transforming the workflow's task relation/definition JSON into TaskNode list yields zero task nodes. DolphinScheduler requires every saved workflow to contain at least one task node so a valid DAG can be built. Saving or validating a workflow whose 'tasks'/'taskDefinitions' JSON is empty triggers this error.","triggerScenarios":"Calling createWorkflowDefinition/updateWorkflowDefinition (or importWorkflow) with a taskRelationJson/taskDefinitionJson that decodes to an empty list, e.g. workflowJson with no task objects, or JSON that fails to map into WorkflowTaskRelation/TaskDefinitionLog entries.","commonSituations":"Hand-editing workflow JSON and deleting all tasks; importing an exported workflow that lost its task list; programmatic API calls that build an empty task array; corrupted UI-generated JSON.","solutions":["Add at least one task node to the workflow definition JSON before saving (populate taskDefinitions and the corresponding taskRelations).","Validate the workflow JSON with JSONUtils or the UI designer before submitting the create/update API call.","Check that taskDefinitionJson entries parse correctly (correct field names/types) so transformTask does not silently produce an empty node list.","If importing, re-export the workflow from a healthy environment and verify the tasks section is non-empty."],"exampleFix":"// before\nString json = \"{\\\"globalParams\\\":[],\\\"tasks\\\":[]}\";\nworkflowDefinitionService.createWorkflowDefinition(user, projectCode, name, json, ...);\n// after\nString json = \"{\\\"globalParams\\\":[],\\\"tasks\\\":[{\\\"name\\\":\\\"shell_task\\\",\\\"taskType\\\":\\\"SHELL\\\",...}]}\";\nworkflowDefinitionService.createWorkflowDefinition(user, projectCode, name, json, ...);","handlingStrategy":"validation","validationCode":"WorkflowTaskRelationList relations = JSONUtils.toList(taskRelationJson, WorkflowTaskRelation.class);\nif (relations == null || relations.isEmpty() || taskDefinitionJsonList.isEmpty()) {\n    throw new IllegalArgumentException(\"workflow must contain at least one task\");\n}","typeGuard":"boolean hasTasks(String workflowJson) {\n  List<TaskDefinitionLog> tasks = JSONUtils.toList(\n      JSONUtils.getNodeString(workflowJson, \"taskDefinitionJson\"), TaskDefinitionLog.class);\n  return tasks != null && !tasks.isEmpty();\n}","tryCatchPattern":"try {\n    saveWorkflow(json);\n} catch (ServiceException e) {\n    if (e.getCode() == Status.WORKFLOW_DAG_IS_EMPTY.getCode()) {\n        // surface 'workflow must have at least one task' to the user\n    } else throw e;\n}","preventionTips":["Always build workflows through the UI designer or an export/import round-trip, never empty task arrays","Validate the JSON schema client-side before each save","Add an integration test that round-trips create+query for every generated workflow"],"tags":["workflow-definition","validation","empty-dag"],"backgroundTag":"empty-required-field","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}