iflytek/astron-agent · error · BusinessException

WORKFLOW_PROTOCOL_EMPTY

WORKFLOW_PROTOCOL_EMPTY

Error message

ResponseEnum.WORKFLOW_PROTOCOL_EMPTY

What it means

WORKFLOW_PROTOCOL_EMPTY indicates the workflow's serialized protocol payload (the `data` column) is null or blank when the service needs to parse it into BizWorkflowData. The platform treats a workflow without graph data as unusable, so isSimpleIo refuses to proceed rather than risk a NullPointerException on JSON.parseObject. It is thrown before any node inspection happens.

Solutions

  1. Confirm the workflow actually has graph content: query the workflow table and check `data` is non-null/non-empty for that id
  2. If the workflow is legitimately empty, open it in the editor and save at least a start/end node so the protocol is persisted
  3. Fix the creation/import path so it writes `data` atomically with the row instead of inserting a null-protocol record first
  4. Catch BusinessException with code WORKFLOW_PROTOCOL_EMPTY in the controller and return 400 telling the user the workflow graph is missing

Example fix

// before
Workflow wf = workflowService.getById(id);
boolean simple = workflowService.isSimpleIo(wf.getId()); // throws if data==null
// after
Workflow wf = workflowService.getById(id);
if (wf == null || StringUtils.isBlank(wf.getData())) {
    throw new BusinessException(ResponseEnum.WORKFLOW_PROTOCOL_EMPTY);
}
boolean simple = workflowService.isSimpleIo(wf.getId());
Defensive patterns

Strategy: validation

Validate before calling

Workflow wf = workflowService.getById(id);
if (wf == null) throw new BusinessException(ResponseEnum.WORKFLOW_NOT_EXIST);
if (StringUtils.isBlank(wf.getData())) throw new BusinessException(ResponseEnum.WORKFLOW_PROTOCOL_EMPTY);

Type guard

boolean hasProtocol(Workflow wf) { return wf != null && StringUtils.isNotBlank(wf.getData()); }

Try / catch

try { service.isSimpleIo(id); } catch (BusinessException e) { if ("WORKFLOW_PROTOCOL_EMPTY".equals(e.getCode().toString())) { /* treat as empty graph: return 400 */ } else throw e; }

Prevention

When it happens

Trigger: Calling isSimpleIo(id) for a workflow whose `data` field is null — e.g. a just-created workflow row that has not been saved with graph content yet, a row whose protocol was wiped by a failed save/import, or an id pointing at a stub/migration placeholder record that passes the belong-check.

Common situations: Fetching a workflow created through an API path that inserts the row before the canvas first save; data migrated from an older schema where `data` was nullable; a test fixture with only id/flowId set; DB truncation or partial import leaving an empty protocol.

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

Appendix: source

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

    }

    private void assertSpacePublishManager(Long spaceId) {
        if (spaceId == null) {
            return;
        }
        SpaceRoleEnum role = spaceUserService.getRole(spaceId, UserInfoManagerHandler.getUserId());
        if (SpaceRoleEnum.OWNER != role && SpaceRoleEnum.ADMIN != role) {
            throw new BusinessException(ResponseEnum.INSUFFICIENT_PERMISSIONS);
        }
    }

    public boolean isSimpleIo(Long id) {
        Workflow workflow = getById(id);
        dataPermissionCheckTool.checkWorkflowBelong(workflow, SpaceInfoUtil.getSpaceId());

        String data = workflow.getData();
        if (data == null) {
            throw new BusinessException(ResponseEnum.WORKFLOW_PROTOCOL_EMPTY);
        }

        // Get start and end nodes
        BizWorkflowData bizWorkflowData = JSON.parseObject(data, BizWorkflowData.class);
        List<BizWorkflowNode> nodes = bizWorkflowData.getNodes();
        BizWorkflowNode start = nodes.get(0);
        BizWorkflowNode end = nodes.get(1);
        if (!start.getId().startsWith(WorkflowConst.NodeType.START)) {
            for (BizWorkflowNode node : nodes) {
                if (node.getId().startsWith(WorkflowConst.NodeType.START)) {
                    start = node;
                    break;
                }
            }
        }
        if (!end.getId().startsWith(WorkflowConst.NodeType.END)) {
            for (BizWorkflowNode node : nodes) {
                if (node.getId().startsWith(WorkflowConst.NodeType.END)) {

View on GitHub (pinned to 5e758547a8)