{"record":{"id":"0e17574f6b8bc11b","repo":"iflytek/astron-agent","slug":"toolbox-already-collect","errorCode":"TOOLBOX_ALREADY_COLLECT","errorMessage":"BusinessException(ResponseEnum.TOOLBOX_ALREADY_COLLECT)","messagePattern":"BusinessException\\(ResponseEnum\\.TOOLBOX_ALREADY_COLLECT\\)","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"warning","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/tool/ToolBoxService.java","lineNumber":1240,"sourceCode":"     * @return\n     */\n\n    public Integer favorite(String toolId, Integer favoriteFlag, Boolean isMcp) {\n        AtomicReference<Integer> result = new AtomicReference<>();\n        result.set(0);\n        String userId = UserInfoManagerHandler.getUserId();\n        String redisKey = FAVORITE_KEY_PREFIX + userId;\n        Optional<UserFavoriteTool> existingFavorite;\n        if (isMcp) {\n            existingFavorite = userFavoriteToolMapper.findByUserIdAndMcpToolId(userId, toolId);\n        } else {\n            existingFavorite = userFavoriteToolMapper.findByUserIdAndToolId(userId, toolId);\n        }\n        // 0-favorite, 1-unfavorite\n        if (favoriteFlag == 0) {\n            // Already favorited\n            if (existingFavorite.isPresent()) {\n                throw new BusinessException(ResponseEnum.TOOLBOX_ALREADY_COLLECT);\n            }\n            UserFavoriteTool userFavorite = new UserFavoriteTool();\n            userFavorite.setUserId(userId);\n            userFavorite.setToolId(0L);\n            if (isMcp) {\n                userFavorite.setMcpToolId(toolId);\n            } else {\n                userFavorite.setPluginToolId(toolId);\n            }\n            userFavorite.setCreatedTime(new Timestamp(System.currentTimeMillis()));\n            // 1-indicates favorite\n            userFavorite.setUseFlag(1);\n            userFavoriteToolMapper.save(userFavorite);\n            redisTemplate.opsForSet().add(redisKey, toolId);\n        } else if (favoriteFlag == 1) {\n            if (existingFavorite.isPresent()) {\n                UserFavoriteTool userFavorite = existingFavorite.get();\n                userFavorite.setDeleted(true);","sourceCodeStart":1222,"sourceCodeEnd":1258,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/tool/ToolBoxService.java#L1222-L1258","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the user's favorite list before calling favorite; skip if the tool is already present.","Treat this error as success if the end state (favorited) is what the user wanted.","Fix the UI to disable the favorite button (or flip to unfavorite) immediately after a successful favorite.","If state is inconsistent, call unfavorite first (favoriteFlag=1) then favorite again."],"exampleFix":"// before\nuserFavoriteToolMapper.findByUserIdAndToolId(userId, toolId)\n    .ifPresentOrElse(f -> {}, f -> favoriteService.add(userId, toolId));\n// after\nif (userFavoriteToolMapper.findByUserIdAndToolId(userId, toolId).isEmpty()) {\n    favoriteService.add(userId, toolId); // only favorite when absent\n}","handlingStrategy":"validation","validationCode":"boolean alreadyFavorited = userFavoriteToolMapper.findByUserIdAndToolId(userId, toolId).isPresent();\nif (!alreadyFavorited) { /* safe to send favoriteFlag=0 */ }","typeGuard":null,"tryCatchPattern":"try {\n    favoriteService.setFavorite(userId, toolId, 0);\n} catch (BusinessException e) {\n    if (\"TOOLBOX_ALREADY_COLLECT\".equals(e.getCode())) {\n        // already favorited; sync UI state to favorited\n    }\n}","preventionTips":["Sync the favorite toggle state from the server before rendering it.","Debounce/disable the favorite button while a request is in flight.","Treat duplicate favorite errors as success to keep UI and server consistent."],"tags":["favorites","duplicate-operation","idempotency"],"backgroundTag":"invalid-state-transition","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}