{"record":{"id":"87b3e8f62a616867","repo":"iflytek/astron-agent","slug":"workflow-protocol-node-info-cannot-empty","errorCode":"WORKFLOW_PROTOCOL_NODE_INFO_CANNOT_EMPTY","errorMessage":"ResponseEnum.WORKFLOW_PROTOCOL_NODE_INFO_CANNOT_EMPTY","messagePattern":"ResponseEnum\\.WORKFLOW_PROTOCOL_NODE_INFO_CANNOT_EMPTY","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowService.java","lineNumber":2125,"sourceCode":"            mergeJsonNodes(original, updateNode);\n            workflow.setAdvancedConfig(mapper.writeValueAsString(original));\n        } catch (Exception ex) {\n            log.error(\n                    \"update advancedConfig failed, originalBytes = {}, updateBytes = {}, errorType = {}\",\n                    originalBytes,\n                    updateBytes,\n                    ex.getClass().getSimpleName());\n            throw new BusinessException(ResponseEnum.WORKFLOW_HIGH_PARAM_FAILED);\n        }\n    }\n\n    // ========== 4. Write protocol data (including validation and length limits) ==========\n    private void writeProtocolDataIfPresent(Workflow workflow, BizWorkflowData bizWorkflowData) {\n        if (bizWorkflowData == null) {\n            return;\n        }\n        if (CollectionUtils.isEmpty(bizWorkflowData.getNodes())) {\n            throw new BusinessException(ResponseEnum.WORKFLOW_PROTOCOL_NODE_INFO_CANNOT_EMPTY);\n        }\n        String dataString = JSON.toJSONString(bizWorkflowData);\n        if (dataString.getBytes(StandardCharsets.UTF_8).length > CommonConst.MEDIUM_TEXT_BYTES_LIMIT) {\n            throw new BusinessException(ResponseEnum.WORKFLOW_PROTOCOL_LENGTH_LIMIT);\n        }\n        String old = workflow.getData();\n        if (StringUtils.isNotEmpty(old)) {\n            JSONObject dataInfo = JSON.parseObject(old);\n            dataInfo.put(\"nodes\", bizWorkflowData.getNodes());\n            dataInfo.put(\"edges\", bizWorkflowData.getEdges());\n            workflow.setData(JSON.toJSONString(dataInfo));\n        } else {\n            workflow.setData(dataString);\n        }\n    }\n\n    // ========== 5. SSRF/URL validation ==========\n    private void validateSsrfForNodes(BizWorkflowData bizWorkflowData) {","sourceCodeStart":2107,"sourceCodeEnd":2143,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowService.java#L2107-L2143","documentation":"Thrown by writeProtocolDataIfPresent when the incoming BizWorkflowData has a null or empty nodes list. A workflow protocol payload must contain at least one node to be persisted; an empty graph is rejected. This is a validation gate before serializing the protocol data.","triggerScenarios":"Calling the workflow save/update API with data present but data.nodes == null or an empty array; a frontend sending cleared canvases; an import that produced a node-less graph.","commonSituations":"User cleared all nodes in the editor and hit save; buggy export/import produced {\"nodes\":[]}; deserialization dropped nodes due to a schema mismatch.","solutions":["Ensure the request payload includes at least one node in data.nodes before saving","On the client, block save when the canvas has no nodes and show a validation message","Check that the exporter/importer populates the nodes array correctly","If clearing is intended, delete the workflow rather than saving an empty graph"],"exampleFix":"// before\n{\"data\":{\"nodes\":[],\"edges\":[]}}\n// after\n{\"data\":{\"nodes\":[{\"id\":\"start\",\"type\":\"start\"}],\"edges\":[]}}","handlingStrategy":"validation","validationCode":"if (data == null || data.getNodes() == null || data.getNodes().isEmpty()) { throw new IllegalArgumentException(\"workflow must contain at least one node\"); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Block save in the editor while the canvas has zero nodes","Validate imported JSON contains a non-empty nodes array","Round-trip test export/import to ensure nodes survive serialization"],"tags":["validation","workflow","empty-payload"],"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"}