{"record":{"id":"e29b6809e8ae13ef","repo":"apache/shenyu","slug":"unique-index-conflict-please-enter-again","errorCode":null,"errorMessage":"unique index conflict, please enter again","messagePattern":"unique index conflict, please enter again","errorType":"validation","errorClass":"ShenyuException","httpStatus":null,"severity":"error","filePath":"shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/AiProxyApiKeyServiceImpl.java","lineNumber":98,"sourceCode":"        if (StringUtils.isBlank(entity.getId())) {\n            entity.setId(UUIDUtils.getInstance().generateShortUuid());\n        }\n        if (StringUtils.isBlank(entity.getProxyApiKey())) {\n            entity.setProxyApiKey(SignUtils.generateKey());\n        }\n        // validate namespace\n        if (StringUtils.isBlank(entity.getNamespaceId())) {\n            throw new ShenyuException(ShenyuResultMessage.PARAMETER_ERROR);\n        }\n        // validate selector id\n        if (StringUtils.isBlank(selectorId)) {\n            throw new ShenyuException(ShenyuResultMessage.PARAMETER_ERROR);\n        }\n        entity.setSelectorId(selectorId);\n        // unique check for proxyApiKey if provided\n        if (StringUtils.isNotBlank(entity.getProxyApiKey())\n                && Boolean.TRUE.equals(mapper.proxyApiKeyExisted(selectorId, entity.getProxyApiKey()))) {\n            throw new ShenyuException(ShenyuResultMessage.UNIQUE_INDEX_CONFLICT_ERROR);\n        }\n        if (Objects.isNull(entity.getEnabled())) {\n            entity.setEnabled(Boolean.TRUE);\n        }\n        // back fill generated fields to response dto first\n        dto.setId(entity.getId());\n        dto.setProxyApiKey(entity.getProxyApiKey());\n        dto.setEnabled(entity.getEnabled());\n        final int rows = mapper.insert(entity);\n        publishChange(DataEventTypeEnum.CREATE, entity);\n        return rows;\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public int update(final ProxyApiKeyDTO dto) {\n        final ProxyApiKeyDO entity = ProxyApiKeyTransfer.INSTANCE.mapToEntity(dto);\n        // id is required for update","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/AiProxyApiKeyServiceImpl.java#L80-L116","documentation":"AiProxyApiKeyServiceImpl.create() enforces uniqueness of proxyApiKey within a selector: if the client supplied a key that mapper.proxyApiKeyExisted() already finds for this selector, ShenyuResultMessage.UNIQUE_INDEX_CONFLICT_ERROR is thrown. Note the key is auto-generated only when blank, so an explicitly supplied duplicate is the only way to hit this path.","triggerScenarios":"Creating a second API key for the same selector with proxyApiKey set to a key that already exists on that selector; replaying a create request with the same explicit key after the first succeeded; importing/exporting config containing duplicate keys.","commonSituations":"Operators manually re-entering a key they copied earlier; config restore scripts re-importing keys idempotently without checking existence; concurrent create calls racing between the uniqueness check and insert.","solutions":["Omit proxyApiKey in the create payload so the server auto-generates a unique key via SignUtils.generateKey().","Supply a different, unused key value.","Query existing keys for the selector first and either update the existing record instead of creating a new one.","Client-side: treat ShenyuResultMessage.UNIQUE_INDEX_CONFLICT_ERROR as 'record already exists' and fall back to an update call."],"exampleFix":"// before\nPOST /ai-proxy-key {\"proxyApiKey\":\"sk-existing\",\"namespaceId\":\"ns1\"} // selector sel1, duplicate key\n// after\nPOST /ai-proxy-key {\"namespaceId\":\"ns1\"} // proxyApiKey omitted, server generates unique key","handlingStrategy":"try-catch","validationCode":"// check uniqueness before creating\nif (StringUtils.isNotBlank(dto.getProxyApiKey())\n        && apiKeyMapper.proxyApiKeyExisted(selectorId, dto.getProxyApiKey())) {\n    // record already exists — update instead of create\n}","typeGuard":null,"tryCatchPattern":"try {\n    apiKeyService.createOrUpdate(dto, selectorId);\n} catch (ShenyuException e) {\n    if (ShenyuResultMessage.UNIQUE_INDEX_CONFLICT_ERROR.equals(e.getMessage())) {\n        // fall back to update of the existing key for this selector\n    }\n    throw e;\n}","preventionTips":["Prefer omitting proxyApiKey so the server generates a unique key automatically.","Make import scripts idempotent: look up by (selectorId, proxyApiKey) before insert.","Keep a server-side unique index on (selector_id, proxy_api_key) as the final guard."],"tags":["uniqueness","conflict","admin-api"],"backgroundTag":"file-already-exists","analyzedSha":"567142e07261b3e615ae8850b30f4421f455cc5d","analyzedAt":"2026-09-12T10:08:21.293Z","contentChangedAt":"2026-09-12T10:08:21.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}