apache/druid · error · BasicSecurityDBResourceException
Role [%s] already exists.
Error message
Role [%s] already exists.
What it means
BasicSecurityDBResourceException thrown by createRoleOnce when a role with the requested name already exists in the authorizer's role map. Role names are unique within an authorizer, and the coordinator refuses to create duplicates so existing permissions are never silently overwritten. It is a client-input/validation error surfaced via the coordinator API.
Source
Thrown at extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/db/updater/CoordinatorBasicAuthorizerMetadataStorageUpdater.java:924
private boolean createGroupMappingOnce(String prefix, BasicAuthorizerGroupMapping groupMapping)
{
byte[] oldValue = getCurrentGroupMappingMapBytes(prefix);
Map<String, BasicAuthorizerGroupMapping> groupMappingMap = BasicAuthUtils.deserializeAuthorizerGroupMappingMap(objectMapper, oldValue);
if (groupMappingMap.get(groupMapping.getName()) != null) {
throw new BasicSecurityDBResourceException("Group mapping [%s] already exists.", groupMapping.getName());
} else {
groupMappingMap.put(groupMapping.getName(), groupMapping);
}
byte[] newValue = BasicAuthUtils.serializeAuthorizerGroupMappingMap(objectMapper, groupMappingMap);
return tryUpdateGroupMappingMap(prefix, groupMappingMap, oldValue, newValue);
}
private boolean createRoleOnce(String prefix, String roleName)
{
byte[] oldValue = getCurrentRoleMapBytes(prefix);
Map<String, BasicAuthorizerRole> roleMap = BasicAuthUtils.deserializeAuthorizerRoleMap(objectMapper, oldValue);
if (roleMap.get(roleName) != null) {
throw new BasicSecurityDBResourceException("Role [%s] already exists.", roleName);
} else {
roleMap.put(roleName, new BasicAuthorizerRole(roleName, null));
}
byte[] newValue = BasicAuthUtils.serializeAuthorizerRoleMap(objectMapper, roleMap);
return tryUpdateRoleMap(prefix, roleMap, oldValue, newValue);
}
private boolean deleteRoleOnce(String prefix, String roleName)
{
byte[] oldRoleMapValue = getCurrentRoleMapBytes(prefix);
Map<String, BasicAuthorizerRole> roleMap = BasicAuthUtils.deserializeAuthorizerRoleMap(
objectMapper,
oldRoleMapValue
);
if (roleMap.get(roleName) == null) {
throw new BasicSecurityDBResourceException("Role [%s] does not exist.", roleName);
} else {
roleMap.remove(roleName);View on GitHub (pinned to 9b90983fd2)
Solutions
- Check role existence via GET /druid-ext/basic-security/authorization/db/<authorizer>/roles/<roleName> first
- Use the update API to modify permissions of an existing role instead of create
- Skip creation when the role already exists in automation scripts
- Delete the existing role (checking user assignments first) if a fresh role is required
Example fix
// before
createRole("default", "readRole");
// after
if (!roleExists("default", "readRole")) {
createRole("default", "readRole");
} Defensive patterns
Strategy: validation
Validate before calling
boolean exists = getRoles("default").stream()
.anyMatch(r -> r.equals(roleName));
if (exists) skipCreation(roleName); Try / catch
try {
client.createRole("default", roleName);
} catch (BasicSecurityDBResourceException e) {
if (e.getMessage().contains("already exists")) {
log.info("Role {} already exists", roleName);
} else { throw e; }
} Prevention
- Check role existence via GET before creating
- Use the update endpoint to change permissions of existing roles
- Sequence role creation before user/role assignments in scripts
When it happens
Trigger: POST /druid-ext/basic-security/authorization/db/<authorizer>/roles/<roleName> for a role that already exists.
Common situations: Idempotency issues in provisioning scripts that define roles; re-importing a role export that already exists; multiple admins creating the same role concurrently; calling create when the intent was to update the role's permissions.
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
- User [%s] already exists.
- Group mapping [%s] already exists.
- User [%s] already has role [%s].
- Group mapping [%s] does not exist.
- Role [%s] does not exist.
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/2be0d4980b3583b4.
Report an issue: GitHub.