{"record":{"id":"e2a252598f42edb6","repo":"iflytek/astron-agent","slug":"bot-chain-update-error","errorCode":"BOT_CHAIN_UPDATE_ERROR","errorMessage":"BOT_CHAIN_UPDATE_ERROR","messagePattern":"BOT_CHAIN_UPDATE_ERROR","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/workflow/impl/BotChainServiceImpl.java","lineNumber":85,"sourceCode":"     *\n     * @return\n     */\n    @Override\n    @Transactional\n    public Long cloneWorkFlow(String uid, Long sourceId, Long targetId, HttpServletRequest request, Long spaceId, Integer version, TalkAgentConfigDto talkAgentConfig) {\n        // Query source assistant\n        List<UserLangChainInfo> botList = userLangChainDataService.findListByBotId(Math.toIntExact(sourceId));\n        if (Objects.isNull(botList) || botList.isEmpty()) {\n            log.info(\"***** Source assistant does not exist, id: {}\", sourceId);\n            return null;\n        }\n\n        UserLangChainInfo chainInfo = botList.getFirst();\n        Long massId = Long.valueOf(String.valueOf(chainInfo.getMaasId()));\n        JSONObject res = maasUtil.copyWorkFlow(massId, request, version, targetId, talkAgentConfig);\n        if (Objects.isNull(res)) {\n            // Throw exception to maintain data transactionality\n            throw new BusinessException(ResponseEnum.BOT_CHAIN_UPDATE_ERROR);\n        }\n        JSONObject data = res.getJSONObject(\"data\");\n        Long currentMass = data.getLong(\"id\");\n        String flowId = data.getString(\"flowId\");\n        UserLangChainInfo chain = new UserLangChainInfo();\n        chain.setBotId(Math.toIntExact(targetId));\n        chain.setMaasId(currentMass);\n        chain.setFlowId(flowId);\n        chain.setUid(uid);\n        if (spaceId != null) {\n            chain.setSpaceId(spaceId);\n        }\n        chain.setUpdateTime(LocalDateTime.now());\n        userLangChainDataService.insertUserLangChainInfo(chain);\n        log.info(\"----- Source assistant: {}, target assistant: {} got new canvas id: {}, flowId: {}\", sourceId, targetId, currentMass, flowId);\n        return currentMass;\n    }\n","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/workflow/impl/BotChainServiceImpl.java#L67-L103","documentation":"Thrown by BotChainServiceImpl.cloneWorkFlow when maasUtil.copyWorkFlow returns null, meaning the remote workflow-copy call to the MaaS/Xinghuu service failed to produce a usable response. The method throws BOT_CHAIN_UPDATE_ERROR explicitly so the surrounding @Transactional rolls back the already-created bot record, keeping bot and workflow data consistent.","triggerScenarios":"Copying a workflow for a cloned/derived assistant where maasUtil.copyWorkFlow(massId, request, version, targetId, talkAgentConfig) returns null: upstream MaaS HTTP call failed, returned an error payload, or source chainInfo.getMaasId() was null/garbage producing an invalid copy request.","commonSituations":"The source assistant's maas_id in user_lang_chain_info is stale (upstream workflow deleted); MaaS service down or timing out; the HTTP request context (HttpServletRequest) carries an invalid auth token so the upstream rejects the copy; network partition between console backend and the MaaS service.","solutions":["Check logs immediately before the throw — maasUtil.copyWorkFlow logs why the copy returned null (HTTP status, error body).","Verify the source bot's maas_id exists upstream (query the MaaS/Xinghuu workflow by id); resync or re-import if the workflow was deleted.","Check connectivity/auth between the console backend and the MaaS service; re-login or refresh the forwarded request token if 401.","Retry the clone operation after the upstream recovers; the transactional rollback means no orphan rows remain.","Add a non-null fallback/timeout-retry with backoff in maasUtil.copyWorkFlow for transient upstream failures."],"exampleFix":"// before\nJSONObject res = maasUtil.copyWorkFlow(massId, request, version, targetId, talkAgentConfig);\nif (Objects.isNull(res)) {\n    throw new BusinessException(ResponseEnum.BOT_CHAIN_UPDATE_ERROR);\n}\n// after\nJSONObject res = maasUtil.copyWorkFlow(massId, request, version, targetId, talkAgentConfig);\nif (Objects.isNull(res) || Objects.isNull(res.getJSONObject(\"data\"))) {\n    log.error(\"Workflow copy failed or returned empty payload: sourceBotId={}, maasId={}\", sourceId, massId);\n    throw new BusinessException(ResponseEnum.BOT_CHAIN_UPDATE_ERROR); // transaction rolls back target bot\n}","handlingStrategy":"try-catch","validationCode":"// before cloning, verify the source has a usable upstream workflow\nUserLangChainInfo src = userLangChainDataService.findListByBotId(sourceId).getFirst();\nif (src.getMaasId() == null || !maasUtil.workflowExists(src.getMaasId())) {\n    throw new BusinessException(ResponseEnum.BOT_NOT_EXIST); // fail fast, clearer than BOT_CHAIN_UPDATE_ERROR\n}","typeGuard":null,"tryCatchPattern":"try {\n    Long newMaasId = botChainService.cloneWorkFlow(uid, sourceId, targetId, request, spaceId, version, config);\n} catch (BusinessException e) {\n    // BOT_CHAIN_UPDATE_ERROR: the @Transactional already rolled back the target bot;\n    // check maasUtil logs for the upstream copy failure, then retry after upstream recovers\n}","preventionTips":["Rely on the @Transactional rollback — never persist bot rows manually after a clone failure.","Verify the source bot's maas_id resolves upstream before initiating a clone.","Monitor the console-backend → MaaS service dependency health.","Forward a valid auth context (HttpServletRequest token) to the copy call.","Log the upstream response body on null returns so the failure cause is diagnosable."],"tags":["workflow","maas","transactional","upstream-service"],"backgroundTag":"upstream-api-error","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}