{"record":{"id":"10ac9a98790b02c1","repo":"iflytek/astron-agent","slug":"repo-name-duplicate","errorCode":"REPO_NAME_DUPLICATE","errorMessage":"ResponseEnum.REPO_NAME_DUPLICATE","messagePattern":"ResponseEnum\\.REPO_NAME_DUPLICATE","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"warning","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/repo/RepoService.java","lineNumber":170,"sourceCode":"        String ragflowDatasetId = null;\n        if (ProjectContent.FILE_SOURCE_RAG_FLOW_RAG_STR.equals(repoVO.getTag())) {\n            String datasetName = buildRagflowDatasetName(repoVO.getName(), coreRepoId);\n            ragflowDatasetId = knowledgeV2ServiceCallHandler.createRagflowDataset(datasetName, repoVO.getName());\n        }\n\n        return self.persistRepo(repoVO, spaceId, coreRepoId, ragflowDatasetId);\n    }\n\n    /** Reject duplicate repo names in the current personal or space scope. */\n    private void validateRepoNameUnique(RepoVO repoVO, Long spaceId) {\n        Repo existRepo;\n        if (spaceId == null) {\n            existRepo = this.getOnly(Wrappers.lambdaQuery(Repo.class).eq(Repo::getUserId, UserInfoManagerHandler.getUserId()).eq(Repo::getName, repoVO.getName()).eq(Repo::getDeleted, 0));\n        } else {\n            existRepo = this.getOnly(Wrappers.lambdaQuery(Repo.class).eq(Repo::getSpaceId, spaceId).eq(Repo::getName, repoVO.getName()).eq(Repo::getDeleted, 0));\n        }\n        if (existRepo != null) {\n            throw new BusinessException(ResponseEnum.REPO_NAME_DUPLICATE);\n        }\n    }\n\n    /** Reject unsupported RAG tags. */\n    private void validateTag(String tag) {\n        if (!ProjectContent.isCbgRagCompatible(tag) && !ProjectContent.isAiuiRagCompatible(tag)) {\n            throw new BusinessException(ResponseEnum.REPO_TYPE_NOT_MATCH);\n        }\n    }\n\n    /** Ragflow-RAG always uses a server-generated core repo id. */\n    private String resolveCoreRepoId(RepoVO repoVO) {\n        if (ProjectContent.FILE_SOURCE_RAG_FLOW_RAG_STR.equals(repoVO.getTag())) {\n            return UUID.randomUUID().toString().replace(\"-\", \"\");\n        }\n        if (StringUtils.isEmpty(repoVO.getOuterRepoId())) {\n            return UUID.randomUUID().toString().replace(\"-\", \"\");\n        }","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/repo/RepoService.java#L152-L188","documentation":"RepoService.validateRepoNameUnique() enforces that knowledge-base repo names are unique per owner: when spaceId is null it checks (userId, name, deleted=0), otherwise (spaceId, name, deleted=0). If getOnly finds an existing non-deleted repo with the same name it throws BusinessException(REPO_NAME_DUPLICATE), called from createRepo.","triggerScenarios":"createRepo is called with a name that already exists for the same user (no spaceId) or within the same space: user retries a create after a timeout not knowing the first succeeded, re-creating a repo deleted only logically elsewhere, importing/copying a repo without renaming, or concurrent creates of the same name racing past the check.","commonSituations":"Double-clicking 'Create' in the UI; automation scripts re-running create on retry; switching between personal and space scopes and reusing the same name; soft-deleted rows with deleted=0 check interacting with restore flows.","solutions":["Pick a different repo name, or reuse the existing repo instead of creating a new one (list repos by name first).","Check for an existing repo before creating: query repo by (userId or spaceId, name, deleted=0) in the client and update instead of create.","If the duplicate is a leftover from a failed earlier attempt, delete/rename the old repo then retry.","Guard against race conditions by adding a unique DB constraint on (space_id/user_id, name, deleted) and handling the constraint violation gracefully."],"exampleFix":"// before\nrepoService.createRepo(repoVO); // throws REPO_NAME_DUPLICATE\n\n// after\nRepo existing = repoService.getOnly(Wrappers.lambdaQuery(Repo.class)\n        .eq(Repo::getSpaceId, spaceId)\n        .eq(Repo::getName, repoVO.getName())\n        .eq(Repo::getDeleted, 0));\nif (existing != null) {\n    // reuse existing.getId() or prompt the user for a new name\n} else {\n    repoService.createRepo(repoVO);\n}","handlingStrategy":"validation","validationCode":"Repo existing = repoService.getOnly(Wrappers.lambdaQuery(Repo.class)\n        .eq(spaceId != null, Repo::getSpaceId, spaceId)\n        .eq(spaceId == null, Repo::getUserId, UserInfoManagerHandler.getUserId())\n        .eq(Repo::getName, name)\n        .eq(Repo::getDeleted, 0));\nif (existing != null) { /* reuse existing or ask for a new name */ }","typeGuard":"boolean repoNameTaken(String name, Long spaceId) {\n    return repoService.getOnly(Wrappers.lambdaQuery(Repo.class)\n        .eq(spaceId != null, Repo::getSpaceId, spaceId)\n        .eq(spaceId == null, Repo::getUserId, UserInfoManagerHandler.getUserId())\n        .eq(Repo::getName, name)\n        .eq(Repo::getDeleted, 0)) != null;\n}","tryCatchPattern":"try {\n    repoService.createRepo(repoVO);\n} catch (BusinessException e) {\n    if (ResponseEnum.REPO_NAME_DUPLICATE.getCode().equals(e.getCode())) {\n        // prompt user for a different name or reuse the existing repo\n    } else { throw e; }\n}","preventionTips":["Check name availability client-side before submitting create.","Debounce/disable the create button to prevent double submits.","On retry-after-timeout, query by name first instead of blindly re-creating.","Add a DB unique constraint on (scope, name, deleted) to make uniqueness race-proof."],"tags":["java","duplicate","uniqueness-constraint","repo"],"backgroundTag":"duplicate-entity-name","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"}