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
- 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.
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
- 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.
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)