iflytek/astron-agent · warning · BusinessException

TOOLBOX_ALREADY_COLLECT

TOOLBOX_ALREADY_COLLECT

Error message

BusinessException(ResponseEnum.TOOLBOX_ALREADY_COLLECT)

What it means

The favorite/unfavorite flow throws TOOLBOX_ALREADY_COLLECT when favoriteFlag == 0 (favorite action) but userFavoriteToolMapper.findByUserIdAndToolId already returns a matching UserFavoriteTool row. Favoriting is idempotency-guarded: adding a duplicate favorite for the same tool (or MCP tool) is rejected rather than inserted twice.

Solutions

  1. Check the user's favorite list before calling favorite; skip if the tool is already present.
  2. Treat this error as success if the end state (favorited) is what the user wanted.
  3. Fix the UI to disable the favorite button (or flip to unfavorite) immediately after a successful favorite.
  4. If state is inconsistent, call unfavorite first (favoriteFlag=1) then favorite again.

Example fix

// before
userFavoriteToolMapper.findByUserIdAndToolId(userId, toolId)
    .ifPresentOrElse(f -> {}, f -> favoriteService.add(userId, toolId));
// after
if (userFavoriteToolMapper.findByUserIdAndToolId(userId, toolId).isEmpty()) {
    favoriteService.add(userId, toolId); // only favorite when absent
}
Defensive patterns

Strategy: validation

Validate before calling

boolean alreadyFavorited = userFavoriteToolMapper.findByUserIdAndToolId(userId, toolId).isPresent();
if (!alreadyFavorited) { /* safe to send favoriteFlag=0 */ }

Try / catch

try {
    favoriteService.setFavorite(userId, toolId, 0);
} catch (BusinessException e) {
    if ("TOOLBOX_ALREADY_COLLECT".equals(e.getCode())) {
        // already favorited; sync UI state to favorited
    }
}

Prevention

When it happens

Trigger: Calling the favorite API (favoriteFlag=0) for a tool the user already favorited; double-clicking the favorite button causing a second request; replaying a favorite request in a retry after the first one succeeded.

Common situations: Frontend favorite toggle out of sync with server state (optimistic UI not reverted); automated scripts that favorite tools without checking existing favorites; concurrent favorite calls from multiple tabs.

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/0e17574f6b8bc11b. Report an issue: GitHub.

Appendix: source

Thrown at console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/tool/ToolBoxService.java:1240

     * @return
     */

    public Integer favorite(String toolId, Integer favoriteFlag, Boolean isMcp) {
        AtomicReference<Integer> result = new AtomicReference<>();
        result.set(0);
        String userId = UserInfoManagerHandler.getUserId();
        String redisKey = FAVORITE_KEY_PREFIX + userId;
        Optional<UserFavoriteTool> existingFavorite;
        if (isMcp) {
            existingFavorite = userFavoriteToolMapper.findByUserIdAndMcpToolId(userId, toolId);
        } else {
            existingFavorite = userFavoriteToolMapper.findByUserIdAndToolId(userId, toolId);
        }
        // 0-favorite, 1-unfavorite
        if (favoriteFlag == 0) {
            // Already favorited
            if (existingFavorite.isPresent()) {
                throw new BusinessException(ResponseEnum.TOOLBOX_ALREADY_COLLECT);
            }
            UserFavoriteTool userFavorite = new UserFavoriteTool();
            userFavorite.setUserId(userId);
            userFavorite.setToolId(0L);
            if (isMcp) {
                userFavorite.setMcpToolId(toolId);
            } else {
                userFavorite.setPluginToolId(toolId);
            }
            userFavorite.setCreatedTime(new Timestamp(System.currentTimeMillis()));
            // 1-indicates favorite
            userFavorite.setUseFlag(1);
            userFavoriteToolMapper.save(userFavorite);
            redisTemplate.opsForSet().add(redisKey, toolId);
        } else if (favoriteFlag == 1) {
            if (existingFavorite.isPresent()) {
                UserFavoriteTool userFavorite = existingFavorite.get();
                userFavorite.setDeleted(true);

View on GitHub (pinned to 5e758547a8)