apache/shenyu · error · ShenyuException
unique index conflict, please enter again
Error message
unique index conflict, please enter again
What it means
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.
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.
Example fix
// before
POST /ai-proxy-key {"proxyApiKey":"sk-existing","namespaceId":"ns1"} // selector sel1, duplicate key
// after
POST /ai-proxy-key {"namespaceId":"ns1"} // proxyApiKey omitted, server generates unique key Defensive patterns
Strategy: try-catch
Validate before calling
// check uniqueness before creating
if (StringUtils.isNotBlank(dto.getProxyApiKey())
&& apiKeyMapper.proxyApiKeyExisted(selectorId, dto.getProxyApiKey())) {
// record already exists — update instead of create
} Try / catch
try {
apiKeyService.createOrUpdate(dto, selectorId);
} catch (ShenyuException e) {
if (ShenyuResultMessage.UNIQUE_INDEX_CONFLICT_ERROR.equals(e.getMessage())) {
// fall back to update of the existing key for this selector
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- The user namespace rel is exist!
- registry_id is already exist
- uri validation of Condition failed, please check.
- parameter error
- registry is not exist
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/e29b6809e8ae13ef.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/AiProxyApiKeyServiceImpl.java:98
if (StringUtils.isBlank(entity.getId())) {
entity.setId(UUIDUtils.getInstance().generateShortUuid());
}
if (StringUtils.isBlank(entity.getProxyApiKey())) {
entity.setProxyApiKey(SignUtils.generateKey());
}
// validate namespace
if (StringUtils.isBlank(entity.getNamespaceId())) {
throw new ShenyuException(ShenyuResultMessage.PARAMETER_ERROR);
}
// validate selector id
if (StringUtils.isBlank(selectorId)) {
throw new ShenyuException(ShenyuResultMessage.PARAMETER_ERROR);
}
entity.setSelectorId(selectorId);
// unique check for proxyApiKey if provided
if (StringUtils.isNotBlank(entity.getProxyApiKey())
&& Boolean.TRUE.equals(mapper.proxyApiKeyExisted(selectorId, entity.getProxyApiKey()))) {
throw new ShenyuException(ShenyuResultMessage.UNIQUE_INDEX_CONFLICT_ERROR);
}
if (Objects.isNull(entity.getEnabled())) {
entity.setEnabled(Boolean.TRUE);
}
// back fill generated fields to response dto first
dto.setId(entity.getId());
dto.setProxyApiKey(entity.getProxyApiKey());
dto.setEnabled(entity.getEnabled());
final int rows = mapper.insert(entity);
publishChange(DataEventTypeEnum.CREATE, entity);
return rows;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int update(final ProxyApiKeyDTO dto) {
final ProxyApiKeyDO entity = ProxyApiKeyTransfer.INSTANCE.mapToEntity(dto);
// id is required for updateView on GitHub (pinned to 567142e072)