iflytek/astron-agent · error · BusinessException

TOOLBOX_CANNOT_DELETE_RELATED_WORKFLOW

TOOLBOX_CANNOT_DELETE_RELATED_WORKFLOW

Error message

BusinessException(ResponseEnum.TOOLBOX_CANNOT_DELETE_RELATED_WORKFLOW)

What it means

ToolBoxService.deleteTool throws TOOLBOX_CANNOT_DELETE_RELATED_WORKFLOW when flowToolRelMapper.selectCount finds at least one FlowToolRel row referencing the tool's toolId. Published tools (status != 0) that are bound to one or more workflows are protected from deletion to avoid breaking those workflows. Deletion is refused as a referential-integrity guard.

Solutions

  1. Find and remove the tool from all workflows that reference it, then retry deletion.
  2. If workflows are obsolete, delete them first so their FlowToolRel rows are removed.
  3. Check the flow_tool_rel table (toolId = the tool's toolId) to list blocking workflows.
  4. Keep the tool if it is intentionally shared; deletion of shared published tools should be a deliberate workflow-migration task.

Example fix

// before
toolBoxService.deleteTool(toolId); // fails while workflows reference it
// after
// 1. remove/detach the tool from every workflow referencing it
// 2. then delete
long refs = flowToolRelMapper.selectCount(
    Wrappers.lambdaQuery(FlowToolRel.class).eq(FlowToolRel::getToolId, toolId));
if (refs == 0) {
    toolBoxService.deleteTool(toolId);
}
Defensive patterns

Strategy: validation

Validate before calling

long flowRefs = flowToolRelMapper.selectCount(
    Wrappers.lambdaQuery(FlowToolRel.class).eq(FlowToolRel::getToolId, toolId));
if (flowRefs > 0) { /* block delete; list blocking workflows to the user */ }

Try / catch

try {
    toolBoxService.deleteTool(id);
} catch (BusinessException e) {
    if ("TOOLBOX_CANNOT_DELETE_RELATED_WORKFLOW".equals(e.getCode())) {
        // surface list of workflows using this tool
    }
}

Prevention

When it happens

Trigger: Calling deleteTool for a published tool whose toolId appears in the flow_tool_rel table; attempting to remove a tool currently used by any workflow (agent flow) in the space.

Common situations: User tries to clean up a tool still wired into live workflows; reorganization/deprecation of shared tools that multiple workflows depend on; automated garbage-collection of tools without checking references first.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/tool/ToolBoxService.java:441

    @Transactional
    public Object deleteTool(Long id) {
        ToolBox toolBox = getById(id);
        if (toolBox == null) {
            throw new BusinessException(ResponseEnum.TOOLBOX_NOT_EXIST_DELETE);
        }
        dataPermissionCheckTool.checkToolBelong(toolBox);
        // Delete draft tools directly
        if (toolBox.getStatus().equals(0)) {
            toolBox.setDeleted(true);
            toolBox.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            updateById(toolBox);
            return ApiResult.success();
        }

        long flowListCount = flowToolRelMapper.selectCount(Wrappers.lambdaQuery(FlowToolRel.class).eq(FlowToolRel::getToolId, toolBox.getToolId()));
        if (flowListCount > 0) {
            throw new BusinessException(ResponseEnum.TOOLBOX_CANNOT_DELETE_RELATED_WORKFLOW);
        }

        long modelListCount = botToolRelService.count(Wrappers.lambdaQuery(BotToolRel.class).eq(BotToolRel::getToolId, toolBox.getToolId()));
        if (modelListCount > 0) {
            throw new BusinessException(ResponseEnum.TOOLBOX_CANNOT_DELETE_RELATED);
        }

        toolBoxMapper.update(null, new UpdateWrapper<ToolBox>().lambda()
                .set(ToolBox::getDeleted, true)
                .set(ToolBox::getUpdateTime, new Timestamp(System.currentTimeMillis()))
                .eq(ToolBox::getToolId, toolBox.getToolId()));

        String paramStr = "?app_id=" + commonConfig.getAppId() + "&tool_ids=" + toolBox.getToolId();
        ToolResp toolDelResp = toolServiceCallHandler.toolDelete(paramStr);
        toolServiceCallHandler.dealResult(toolDelResp);
        return ApiResult.success();
    }

View on GitHub (pinned to 5e758547a8)