{"record":{"id":"64ddbeb2456ef815","repo":"iflytek/astron-agent","slug":"bot-api-create-limit-error","errorCode":"BOT_API_CREATE_LIMIT_ERROR","errorMessage":"BOT_API_CREATE_LIMIT_ERROR","messagePattern":"BOT_API_CREATE_LIMIT_ERROR","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"warning","filePath":"console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/publish/impl/PublishApiServiceImpl.java","lineNumber":143,"sourceCode":"    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public BotApiInfoDTO createBotApi(CreateBotApiVo createBotApiVo, HttpServletRequest request, String uid) {\n        return createBotApi(createBotApiVo, request, uid, SpaceInfoUtil.getSpaceId());\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public BotApiInfoDTO createBotApi(CreateBotApiVo createBotApiVo, HttpServletRequest request, String uid, Long spaceId) {\n        String uuid = UUID.randomUUID().toString();\n\n        ChatBotBase botBase = chatBotDataService.findOne(uid, createBotApiVo.getBotId(), spaceId);\n        AppMst appMst = appMstService.getByAppId(uid, createBotApiVo.getAppId());\n        if (Objects.isNull(botBase) || Objects.isNull(appMst)) {\n            throw new BusinessException(ResponseEnum.USER_APP_ID_NOT_EXISTE);\n        }\n\n        if (!redisUtil.tryLock(PUBLISH_API + uid, 3000, uuid)) {\n            throw new BusinessException(ResponseEnum.BOT_API_CREATE_LIMIT_ERROR);\n        }\n        try {\n            List<Integer> maasSupportedVersions = List.of(BotVersionEnum.WORKFLOW.getVersion());\n            if (maasSupportedVersions.contains(botBase.getVersion())) {\n                return createMaasApi(uid, appMst, botBase, spaceId, request);\n            } else {\n                throw new BusinessException(ResponseEnum.BOT_TYPE_NOT_SUPPORT);\n            }\n        } catch (BusinessException e) {\n            throw e;\n        } catch (Exception e) {\n            log.error(\"PublishApiServiceImpl.createBotApi : create Bot api error, request: {}\", createBotApiVo, e);\n            throw new BusinessException(ResponseEnum.BOT_API_CREATE_ERROR);\n        } finally {\n            redisUtil.unlock(PUBLISH_API + uid, uuid);\n        }\n\n    }","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/publish/impl/PublishApiServiceImpl.java#L125-L161","documentation":"BOT_API_CREATE_LIMIT_ERROR is thrown by createBotApi when redisUtil.tryLock(PUBLISH_API + uid, 3000, uuid) fails — another publish-API operation for the same uid already holds the distributed lock (or the lock couldn't be acquired within 3 seconds). It acts as a concurrency guard so one user can't run parallel API-publish flows.","triggerScenarios":"Calling createBotApi while a previous createBotApi for the same uid is still in progress; a crashed request left the lock held until TTL expiry; network latency making the 3000ms wait elapse; rapid double-click submitting two requests.","commonSituations":"User double-submits the publish form; retry storm after a slow publish; Redis lock leak from an instance killed mid-operation (lock persists up to TTL).","solutions":["Retry after the in-flight publish finishes (lock auto-expires after TTL or is released in finally).","Debounce/disable the publish button on the client to prevent double submission.","If locks leak repeatedly, ensure unlock in finally (it is) and consider shortening TTL or adding lock ownership checks.","Check Redis health — latency over ~3s causes false lock conflicts."],"exampleFix":"// before\npublishApiService.createBotApi(vo, request, uid, spaceId); // throws if lock held\n// after\nboolean acquired = false;\nfor (int i = 0; i < 3 && !acquired; i++) {\n    try {\n        publishApiService.createBotApi(vo, request, uid, spaceId);\n        acquired = true;\n    } catch (BusinessException e) {\n        if (!\"BOT_API_CREATE_LIMIT_ERROR\".equals(e.getCode())) throw e;\n        Thread.sleep(3000); // wait for prior publish to release lock\n    }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { publishApiService.createBotApi(vo, request, uid, spaceId); }\ncatch (BusinessException e) {\n    if (e.getCode() == ResponseEnum.BOT_API_CREATE_LIMIT_ERROR) { retryAfterDelay(3000); }\n    else throw e;\n}","preventionTips":["Disable the publish button while a request is in flight (debounce).","Keep lock TTL comfortably above worst-case publish duration.","Monitor Redis latency; slow Redis causes spurious lock conflicts.","Ensure unlock always runs in finally (it does here)."],"tags":["concurrency","redis","lock","rate-limit"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}