{"record":{"id":"e78c4a879ab2e618","repo":"iflytek/astron-agent","slug":"workflowdsl-must-have-at-least-one-node","errorCode":null,"errorMessage":"WorkflowDSL must have at least one node.","messagePattern":"WorkflowDSL must have at least one node\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"core/workflow/engine/dsl_engine.py","lineNumber":1987,"sourceCode":"            sub_dsl = sparkflow_dsl.extract_loop_sub_dsl(loop_node_id)\n        return WorkflowEngineFactory.create_engine(sub_dsl, span)\n\n    @staticmethod\n    def create_debug_node(\n        sparkflow_dsl: WorkflowDSL,\n        span: Span,\n    ) -> BaseNode:\n        \"\"\"\n        Create a debug node.\n\n        :param sparkflow_dsl: Workflow DSL definition\n        :param span: Tracing span for observability\n        :return: BaseNode instance for debugging\n        \"\"\"\n        with span.start() as span_context:\n            builder = WorkflowEngineBuilder(sparkflow_dsl).build_nodes(span_context)\n            if len(sparkflow_dsl.nodes) == 0:\n                raise ValueError(\"WorkflowDSL must have at least one node.\")\n            builder.start_node_id = sparkflow_dsl.nodes[0].id\n            builder.chains = Chains(workflow_schema=sparkflow_dsl)\n            engine = builder.build()\n            if (\n                engine.engine_ctx\n                and builder.start_node_id in engine.engine_ctx.built_nodes\n            ):\n                return engine.engine_ctx.built_nodes[\n                    builder.start_node_id\n                ].node_instance\n            else:\n                raise ValueError(f\"Start node ({builder.start_node_id}) not found.\")\n\n\nclass WorkflowEngineBuilder:\n    \"\"\"\n    Builder for constructing workflow engines.\n","sourceCodeStart":1969,"sourceCodeEnd":2005,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/workflow/engine/dsl_engine.py#L1969-L2005","documentation":"create_debug_node builds a debug node instance from a WorkflowDSL but first requires the DSL to contain at least one node. If sparkflow_dsl.nodes is an empty list, the engine cannot determine a start node, so it raises ValueError. This guards against building an engine with no executable graph.","triggerScenarios":"Calling create_debug_node with a WorkflowDSL whose nodes list is empty — e.g. a DSL constructed programmatically without nodes, or a deserialized DSL from an empty/deleted workflow.","commonSituations":"Debugging a freshly created workflow before any nodes were added on the canvas; frontend sending an empty nodes array in a debug request; DSL export/import losing nodes.","solutions":["Add at least one node to the workflow DSL before calling create_debug_node","Check len(dsl.nodes) > 0 in the caller before invoking","Fix the DSL serialization/deserialization path if nodes were dropped"],"exampleFix":"// before\nengine_node = dsl_engine.create_debug_node(dsl, node_id, span)  # dsl.nodes == []\n// after\nif not dsl.nodes:\n    raise HTTPException(400, \"Workflow has no nodes to debug\")\nengine_node = dsl_engine.create_debug_node(dsl, node_id, span)","handlingStrategy":"validation","validationCode":"if not sparkflow_dsl.nodes:\n    raise ValueError(\"Cannot create debug node: DSL has no nodes\")\nnode = engine.create_debug_node(sparkflow_dsl, node_id, span)","typeGuard":"def has_nodes(dsl) -> bool:\n    return bool(getattr(dsl, \"nodes\", None))","tryCatchPattern":"try:\n    node = engine.create_debug_node(dsl, node_id, span)\nexcept ValueError as e:\n    logger.error(\"debug node creation failed: %s\", e)\n    return None","preventionTips":["Check dsl.nodes is non-empty before any engine call","Never submit debug requests for empty workflows","Guard the API endpoint with a nodes-count check"],"tags":["workflow","dsl","validation"],"backgroundTag":"empty-required-field","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}