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
- Confirm the workflow actually has graph content: query the workflow table and check `data` is non-null/non-empty for that id
- If the workflow is legitimately empty, open it in the editor and save at least a start/end node so the protocol is persisted
- Fix the creation/import path so it writes `data` atomically with the row instead of inserting a null-protocol record first
- 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
- Always save at least a start/end node when creating a workflow before calling read APIs
- Insert workflow rows and their graph data in one transaction
- Add a DB check/constraint or startup audit for workflows with null data
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)