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

  1. Reload the bot's market status before calling offline and only invoke it when ShelfStatusEnum.isOnShelf(status) is true
  2. Handle the error as idempotent: if the bot is already off-shelf, treat the operation as a success/no-op on the caller side
  3. Check for concurrent updates: re-fetch status after the error and confirm another operator did not already take the bot offline
  4. 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

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)