iflytek/astron-agent · warning · BusinessException
BOT_STATUS_NOT_ALLOW_OFFLINE
BOT_STATUS_NOT_ALLOW_OFFLINE
Error message
BOT_STATUS_NOT_ALLOW_OFFLINE
What it means
MarketPublishStrategy.offline() throws BOT_STATUS_NOT_ALLOW_OFFLINE when the bot cannot be taken off the market shelf. After selecting the bot's market record via chatBotMarketMapper.selectBotDetail, the code checks ShelveStatusEnum.isOnShelf(currentStatus); if the record is missing or the bot is not currently on-shelf, an offline operation is an invalid state transition and this error is thrown.
Solutions
- Reload the bot's market status before calling offline and only invoke it when ShelfStatusEnum.isOnShelf(status) is true
- Handle the error as idempotent: if the bot is already off-shelf, treat the operation as a success/no-op on the caller side
- Check for concurrent updates: re-fetch status after the error and confirm another operator did not already take the bot offline
- Fix the data if status is unexpectedly null: verify chat_bot_market has a row for this botId/uid/spaceId and that it was inserted by the publish flow
Example fix
// before
publishStrategy.offline(botId, data, uid, spaceId); // throws if not on shelf
// after
BotPublishQueryResult r = chatBotMarketMapper.selectBotDetail(botId, uid, spaceId);
if (r != null && ShelfStatusEnum.isOnShelf(r.getBotStatus())) {
publishStrategy.offline(botId, data, uid, spaceId);
} Defensive patterns
Strategy: validation
Validate before calling
BotPublishQueryResult r = chatBotMarketMapper.selectBotDetail(botId, uid, spaceId);
if (r == null || !ShelfStatusEnum.isOnShelf(r.getBotStatus())) {
throw new IllegalStateException("Bot is not on the market shelf; offline not applicable");
} Try / catch
try {
publishStrategy.offline(botId, data, uid, spaceId);
} catch (BusinessException e) {
if ("BOT_STATUS_NOT_ALLOW_OFFLINE".equals(e.getCode())) { /* treat as already-offline no-op */ }
else throw e;
} Prevention
- Refresh the bot's market status in the UI right before showing offline actions
- Make offline calls idempotent and tolerate already-off-shelf states
- Serialize concurrent publish/offline operations per bot (lock or optimistic versioning)
When it happens
Trigger: Calling the market offline/publish API for a bot whose market record has a null status or whose status is not ON_SHELF (e.g. bot already off-shelf, never published to market, or removed).
Common situations: Double-clicking/submitting an offline request twice; attempting to unpublish a bot that was never market-published; concurrent offline by two admins so the second call sees OFF_SHELF; stale frontend page showing an on-shelf bot that has since been taken down.
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/09fa30139c7ea5f8.
Report an issue: GitHub.
Appendix: source
Thrown at console/backend/hub/src/main/java/com/iflytek/astron/console/hub/strategy/publish/impl/MarketPublishStrategy.java:116
@Transactional(rollbackFor = Exception.class)
public ApiResult<Object> offline(Integer botId, Object publishData, String currentUid, Long spaceId) {
log.info("Offlining bot from market: botId={}, currentUid={}, spaceId={}", botId, currentUid, spaceId);
try {
// 1. Validate bot permission
int hasPermission = chatBotBaseMapper.checkBotPermission(botId, currentUid, spaceId);
if (hasPermission == 0) {
throw new BusinessException(ResponseEnum.BOT_NOT_EXISTS);
}
// 2. Query current publish status
BotPublishQueryResult queryResult = chatBotMarketMapper.selectBotDetail(botId, currentUid, spaceId);
Integer currentStatus = queryResult != null ? queryResult.getBotStatus() : null;
String currentChannels = queryResult != null ? queryResult.getPublishChannels() : null;
// 3. Validate offline conditions
if (currentStatus == null || !ShelfStatusEnum.isOnShelf(currentStatus)) {
throw new BusinessException(ResponseEnum.BOT_STATUS_NOT_ALLOW_OFFLINE);
}
Integer newStatus = ShelfStatusEnum.OFF_SHELF.getCode();
String newChannels = publishChannelService.updatePublishChannels(
currentChannels, PublishChannelEnum.MARKET.getCode(), false);
// 4. Handle market data synchronization directly (offline operation)
handleBotMarketOffline(botId, currentUid, spaceId, newStatus, newChannels);
// 5. Publish event to trigger bot-type-specific operations if needed
eventPublisher.publishEvent(new BotPublishStatusChangedEvent(
this, botId, currentUid, spaceId, "OFFLINE",
currentStatus, newStatus, newChannels));
log.info("Market offline completed successfully: botId={}", botId);
return ApiResult.success(null);
} catch (Exception e) {View on GitHub (pinned to 5e758547a8)