{"record":{"id":"9518d2c717a687bd","repo":"iflytek/astron-agent","slug":"repo-delete-failed-bot-used","errorCode":"REPO_DELETE_FAILED_BOT_USED","errorMessage":"ResponseEnum.REPO_DELETE_FAILED_BOT_USED","messagePattern":"ResponseEnum\\.REPO_DELETE_FAILED_BOT_USED","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/repo/RepoService.java","lineNumber":941,"sourceCode":"     *         in use by bots\n     */\n    @Transactional\n    public Object deleteRepo(Long id, String tag, HttpServletRequest request) {\n        // Check if tag equals Spark tag\n        if (ProjectContent.isSparkRagCompatible(tag)) {\n            log.info(\"Using Spark deletion logic\");\n            return deleteXinghuoDataset(request, id.toString());\n        }\n        Repo repo = this.getById(id);\n        if (repo == null) {\n            throw new BusinessException(ResponseEnum.REPO_NOT_EXIST);\n        }\n\n        dataPermissionCheckTool.checkRepoBelong(repo);\n\n        long modelListCount = botRepoRelService.count(Wrappers.lambdaQuery(BotRepoRel.class).eq(BotRepoRel::getRepoId, repo.getCoreRepoId()));\n        if (modelListCount > 0) {\n            throw new BusinessException(ResponseEnum.REPO_DELETE_FAILED_BOT_USED);\n        }\n\n        repo.setDeleted(true);\n        this.updateById(repo);\n\n        // Metering rollback\n        List<FileInfoV2> fileInfos = fileInfoV2Mapper.getFileInfoV2ByRepoId(repo.getId());\n        for (FileInfoV2 fileInfoV2 : fileInfos) {\n            fileInfoV2Service.fileCostRollback(fileInfoV2.getUuid());\n        }\n\n        RepoVO repoVO = new RepoVO();\n        repoVO.setId(id);\n        repoVO.setOperType(ProjectContent.REPO_STATUS_DELETE);\n        return this.updateRepoStatus(repoVO);\n    }\n\n    // private JSONObject getKnowledgeQueryObject(String group, Integer topN, String query) {","sourceCodeStart":923,"sourceCodeEnd":959,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/repo/RepoService.java#L923-L959","documentation":"BusinessException REPO_DELETE_FAILED_BOT_USED is thrown by RepoService when attempting to soft-delete a repository (knowledge/repo entity) that is still referenced by at least one bot via the bot_repo_rel relation. The service counts BotRepoRel rows by coreRepoId and refuses deletion if any binding exists, because removing the repo would break bots that depend on it. It is a deliberate referential-integrity guard, not a system fault.","triggerScenarios":"Calling the repo delete API (RepoService.deleteRepo, around RepoService.java:941) for a repo where `botRepoRelService.count(eq BotRepoRel::getRepoId, repo.getCoreRepoId()) > 0`, after the repo-belong permission check passes.","commonSituations":"Users try to delete a knowledge base / repo that is attached to one or more agents (bots) in the console; cleanup scripts that delete repos in bulk without first unbinding them from bots; stale bot-repo relations left over from deleted bots that block deletion.","solutions":["Find the bots using the repo (query BotRepoRel by repoId / coreRepoId) and detach the repo from each bot via the bot edit UI or the bot-repo unbind API.","Re-run the delete once the relation count is 0.","If relations are stale (bots already deleted), clean up orphan BotRepoRel rows, then delete the repo.","If deletion should proceed anyway, first remove bindings programmatically in the same transaction before calling delete."],"exampleFix":"// before\nrepoService.deleteRepo(repoId); // throws REPO_DELETE_FAILED_BOT_USED\n\n// after\nbotRepoRelService.remove(Wrappers.lambdaQuery(BotRepoRel.class).eq(BotRepoRel::getRepoId, repo.getCoreRepoId()));\nrepoService.deleteRepo(repoId);","handlingStrategy":"try-catch","validationCode":"long bound = botRepoRelService.count(Wrappers.lambdaQuery(BotRepoRel.class).eq(BotRepoRel::getRepoId, coreRepoId));\nif (bound > 0) { /* detach bindings or abort */ }","typeGuard":null,"tryCatchPattern":"try {\n    repoService.deleteRepo(repoId);\n} catch (BusinessException e) {\n    if (\"REPO_DELETE_FAILED_BOT_USED\".equals(e.getCode())) {\n        List<BotRepoRel> rels = botRepoRelService.list(...);\n        // prompt user to detach bots, then retry\n    } else throw e;\n}","preventionTips":["List bot bindings in the UI before enabling the delete button; disable it when count > 0.","Clean up bot-repo relations when deleting bots.","In bulk-delete scripts, unbind relations in the same transaction before delete."],"tags":["referential-integrity","repository","bot-binding","delete-blocked"],"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-15T23:17:13.987Z"}