{"record":{"id":"3c8ef411398d63e7","repo":"iflytek/astron-agent","slug":"workflow-skill-api-not-ready","errorCode":"WORKFLOW_SKILL_API_NOT_READY","errorMessage":"WORKFLOW_SKILL_API_NOT_READY","messagePattern":"WORKFLOW_SKILL_API_NOT_READY","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/workflow/impl/WorkflowSkillExportServiceImpl.java","lineNumber":72,"sourceCode":"            throw new BusinessException(ResponseEnum.PARAMETER_ERROR);\n        }\n\n        Workflow workflow = workflowService.getById(request.getWorkflowId());\n        if (workflow == null) {\n            throw new BusinessException(ResponseEnum.BOT_NOT_EXIST);\n        }\n        dataPermissionCheckTool.checkWorkflowBelong(workflow, SpaceInfoUtil.getSpaceId());\n\n        String workflowName = StringUtils.defaultIfBlank(request.getWorkflowName(), workflow.getName());\n        String workflowDescription =\n                StringUtils.defaultIfBlank(request.getWorkflowDescription(), workflow.getDescription());\n        if (StringUtils.isBlank(workflowName) || StringUtils.isBlank(workflowDescription)) {\n            throw new BusinessException(ResponseEnum.WORKFLOW_SKILL_NAME_DESC_EMPTY);\n        }\n\n        BotApiInfoDTO apiInfo = publishApiService.getApiInfo(request.getBotId());\n        if (!hasPublishedApi(apiInfo)) {\n            throw new BusinessException(ResponseEnum.WORKFLOW_SKILL_API_NOT_READY);\n        }\n\n        List<BizInputOutput> inputs = extractWorkflowInputs(workflow);\n        SkillMetadata metadata = generateSkillMetadata(workflowName, workflowDescription, workflow.getId());\n        String content = buildSkillContent(metadata, workflowName, workflowDescription, apiInfo, inputs);\n        return new WorkflowSkillExportResponse(SKILL_FILE_NAME, content, metadata.aiGenerated());\n    }\n\n    private boolean hasPublishedApi(BotApiInfoDTO apiInfo) {\n        return apiInfo != null\n                && StringUtils.isNotBlank(apiInfo.getAppId())\n                && StringUtils.isNotBlank(apiInfo.getAppKey())\n                && StringUtils.isNotBlank(apiInfo.getAppSecret())\n                && StringUtils.isNotBlank(apiInfo.getServiceUrl())\n                && StringUtils.isNotBlank(apiInfo.getFlowId());\n    }\n\n    private List<BizInputOutput> extractWorkflowInputs(Workflow workflow) {","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/workflow/impl/WorkflowSkillExportServiceImpl.java#L54-L90","documentation":"exportSkill requires the target bot to have a published API. It fetches BotApiInfoDTO via publishApiService.getApiInfo(botId) and throws WORKFLOW_SKILL_API_NOT_READY when hasPublishedApi(apiInfo) is false — i.e. no published API endpoint exists for the bot, so a callable skill cannot be generated.","triggerScenarios":"Calling exportSkill for a botId whose bot has never been published, whose publish is still in review/pending, or whose publish channels were all removed so getApiInfo returns null/empty API info.","commonSituations":"User tries to export a skill from a draft-only bot; the bot publish is pending moderation; the bot was taken offline (off-shelf) before export; botId points to a different bot than the one actually published.","solutions":["Publish the bot (e.g. via the market/channel publish flow) and wait until it is on-shelf with an active API, then retry exportSkill.","Check the bot's publish status via the publish-status API before exporting.","Confirm the botId passed is the one that was actually published, not an old or sibling bot.","If publish is stuck in review, contact an admin or check the moderation record for the bot."],"exampleFix":"// before\nexportSkill({botId: draftBotId, workflowId: 456}); // bot never published\n// after\nawait publishApi.publishBot({botId: draftBotId, channel: \"market\"});\nawait waitForPublishComplete(draftBotId);\nexportSkill({botId: draftBotId, workflowId: 456});","handlingStrategy":"validation","validationCode":"BotApiInfoDTO apiInfo = publishApiService.getApiInfo(botId);\nif (apiInfo == null || apiInfo.getApiUrl() == null) {\n    throw new IllegalStateException(\"bot \" + botId + \" has no published API; publish it first\");\n}","typeGuard":"boolean hasPublishedApi(BotApiInfoDTO apiInfo) {\n    return apiInfo != null && StringUtils.isNotBlank(apiInfo.getApiUrl());\n}","tryCatchPattern":"try {\n    return exportSkill(request);\n} catch (BusinessException e) {\n    if (\"WORKFLOW_SKILL_API_NOT_READY\".equals(e.getCode())) {\n        guideUserToPublishBot(request.getBotId());\n    }\n    throw e;\n}","preventionTips":["Publish the bot and confirm on-shelf status before exporting a skill","Gate the export button on the bot's published-API status from the publish-status API","Verify the botId is the one actually published, not a draft duplicate"],"tags":["publish-state","precondition","bot-api","java"],"backgroundTag":"invalid-state-transition","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}