iflytek/astron-agent · error · BusinessException

WORKFLOW_PROTOCOL_NODE_INFO_CANNOT_EMPTY

WORKFLOW_PROTOCOL_NODE_INFO_CANNOT_EMPTY

Error message

ResponseEnum.WORKFLOW_PROTOCOL_NODE_INFO_CANNOT_EMPTY

What it means

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.

Solutions

  1. Ensure the request payload includes at least one node in data.nodes before saving
  2. On the client, block save when the canvas has no nodes and show a validation message
  3. Check that the exporter/importer populates the nodes array correctly
  4. If clearing is intended, delete the workflow rather than saving an empty graph

Example fix

// before
{"data":{"nodes":[],"edges":[]}}
// after
{"data":{"nodes":[{"id":"start","type":"start"}],"edges":[]}}
Defensive patterns

Strategy: validation

Validate before calling

if (data == null || data.getNodes() == null || data.getNodes().isEmpty()) { throw new IllegalArgumentException("workflow must contain at least one node"); }

Prevention

When it happens

Trigger: 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.

Common situations: User cleared all nodes in the editor and hit save; buggy export/import produced {"nodes":[]}; deserialization dropped nodes due to a schema mismatch.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/87b3e8f62a616867. Report an issue: GitHub.

Appendix: source

Thrown at console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowService.java:2125

            mergeJsonNodes(original, updateNode);
            workflow.setAdvancedConfig(mapper.writeValueAsString(original));
        } catch (Exception ex) {
            log.error(
                    "update advancedConfig failed, originalBytes = {}, updateBytes = {}, errorType = {}",
                    originalBytes,
                    updateBytes,
                    ex.getClass().getSimpleName());
            throw new BusinessException(ResponseEnum.WORKFLOW_HIGH_PARAM_FAILED);
        }
    }

    // ========== 4. Write protocol data (including validation and length limits) ==========
    private void writeProtocolDataIfPresent(Workflow workflow, BizWorkflowData bizWorkflowData) {
        if (bizWorkflowData == null) {
            return;
        }
        if (CollectionUtils.isEmpty(bizWorkflowData.getNodes())) {
            throw new BusinessException(ResponseEnum.WORKFLOW_PROTOCOL_NODE_INFO_CANNOT_EMPTY);
        }
        String dataString = JSON.toJSONString(bizWorkflowData);
        if (dataString.getBytes(StandardCharsets.UTF_8).length > CommonConst.MEDIUM_TEXT_BYTES_LIMIT) {
            throw new BusinessException(ResponseEnum.WORKFLOW_PROTOCOL_LENGTH_LIMIT);
        }
        String old = workflow.getData();
        if (StringUtils.isNotEmpty(old)) {
            JSONObject dataInfo = JSON.parseObject(old);
            dataInfo.put("nodes", bizWorkflowData.getNodes());
            dataInfo.put("edges", bizWorkflowData.getEdges());
            workflow.setData(JSON.toJSONString(dataInfo));
        } else {
            workflow.setData(dataString);
        }
    }

    // ========== 5. SSRF/URL validation ==========
    private void validateSsrfForNodes(BizWorkflowData bizWorkflowData) {

View on GitHub (pinned to 5e758547a8)