iflytek/astron-agent · error · BusinessException

BOT_CHAIN_UPDATE_ERROR

BOT_CHAIN_UPDATE_ERROR

Error message

BOT_CHAIN_UPDATE_ERROR

What it means

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.

Solutions

  1. Check logs immediately before the throw — maasUtil.copyWorkFlow logs why the copy returned null (HTTP status, error body).
  2. 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.
  3. Check connectivity/auth between the console backend and the MaaS service; re-login or refresh the forwarded request token if 401.
  4. Retry the clone operation after the upstream recovers; the transactional rollback means no orphan rows remain.
  5. Add a non-null fallback/timeout-retry with backoff in maasUtil.copyWorkFlow for transient upstream failures.

Example fix

// before
JSONObject res = maasUtil.copyWorkFlow(massId, request, version, targetId, talkAgentConfig);
if (Objects.isNull(res)) {
    throw new BusinessException(ResponseEnum.BOT_CHAIN_UPDATE_ERROR);
}
// after
JSONObject res = maasUtil.copyWorkFlow(massId, request, version, targetId, talkAgentConfig);
if (Objects.isNull(res) || Objects.isNull(res.getJSONObject("data"))) {
    log.error("Workflow copy failed or returned empty payload: sourceBotId={}, maasId={}", sourceId, massId);
    throw new BusinessException(ResponseEnum.BOT_CHAIN_UPDATE_ERROR); // transaction rolls back target bot
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before cloning, verify the source has a usable upstream workflow
UserLangChainInfo src = userLangChainDataService.findListByBotId(sourceId).getFirst();
if (src.getMaasId() == null || !maasUtil.workflowExists(src.getMaasId())) {
    throw new BusinessException(ResponseEnum.BOT_NOT_EXIST); // fail fast, clearer than BOT_CHAIN_UPDATE_ERROR
}

Try / catch

try {
    Long newMaasId = botChainService.cloneWorkFlow(uid, sourceId, targetId, request, spaceId, version, config);
} catch (BusinessException e) {
    // BOT_CHAIN_UPDATE_ERROR: the @Transactional already rolled back the target bot;
    // check maasUtil logs for the upstream copy failure, then retry after upstream recovers
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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

Appendix: source

Thrown at console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/workflow/impl/BotChainServiceImpl.java:85

     *
     * @return
     */
    @Override
    @Transactional
    public Long cloneWorkFlow(String uid, Long sourceId, Long targetId, HttpServletRequest request, Long spaceId, Integer version, TalkAgentConfigDto talkAgentConfig) {
        // Query source assistant
        List<UserLangChainInfo> botList = userLangChainDataService.findListByBotId(Math.toIntExact(sourceId));
        if (Objects.isNull(botList) || botList.isEmpty()) {
            log.info("***** Source assistant does not exist, id: {}", sourceId);
            return null;
        }

        UserLangChainInfo chainInfo = botList.getFirst();
        Long massId = Long.valueOf(String.valueOf(chainInfo.getMaasId()));
        JSONObject res = maasUtil.copyWorkFlow(massId, request, version, targetId, talkAgentConfig);
        if (Objects.isNull(res)) {
            // Throw exception to maintain data transactionality
            throw new BusinessException(ResponseEnum.BOT_CHAIN_UPDATE_ERROR);
        }
        JSONObject data = res.getJSONObject("data");
        Long currentMass = data.getLong("id");
        String flowId = data.getString("flowId");
        UserLangChainInfo chain = new UserLangChainInfo();
        chain.setBotId(Math.toIntExact(targetId));
        chain.setMaasId(currentMass);
        chain.setFlowId(flowId);
        chain.setUid(uid);
        if (spaceId != null) {
            chain.setSpaceId(spaceId);
        }
        chain.setUpdateTime(LocalDateTime.now());
        userLangChainDataService.insertUserLangChainInfo(chain);
        log.info("----- Source assistant: {}, target assistant: {} got new canvas id: {}, flowId: {}", sourceId, targetId, currentMass, flowId);
        return currentMass;
    }

View on GitHub (pinned to 5e758547a8)