apache/druid · error · BasicSecurityDBResourceException
Role [%s] does not exist.
Error message
Role [%s] does not exist.
What it means
BasicSecurityDBResourceException thrown during role deletion when the role is not present in the authorizer's role map. The coordinator validates the role exists before removing it and before cleaning up user assignments, aborting the whole operation if it is missing. Signals a stale name reference or wrong authorizer, not a store failure.
Source
Thrown at extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/db/updater/CoordinatorBasicAuthorizerMetadataStorageUpdater.java:940
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);
}
byte[] oldUserMapValue = getCurrentUserMapBytes(prefix);
Map<String, BasicAuthorizerUser> userMap = BasicAuthUtils.deserializeAuthorizerUserMap(
objectMapper,
oldUserMapValue
);
for (BasicAuthorizerUser user : userMap.values()) {
user.getRoles().remove(roleName);
}
byte[] newUserMapValue = BasicAuthUtils.serializeAuthorizerUserMap(objectMapper, userMap);
byte[] oldGroupMapValue = getCurrentGroupMappingMapBytes(prefix);
Map<String, BasicAuthorizerGroupMapping> groupMap = BasicAuthUtils.deserializeAuthorizerGroupMappingMap(
objectMapper,
oldGroupMapValueView on GitHub (pinned to 9b90983fd2)
Solutions
- Confirm the role exists with GET /druid-ext/basic-security/authorization/db/<authorizer>/roles before deleting
- Make deletion idempotent in scripts by tolerating 'does not exist'
- Verify the authorizer name in the request path
- Re-create the role if it was deleted accidentally
Example fix
// before
client.deleteRole("default", "readRole");
// after
if (roleExists("default", "readRole")) {
client.deleteRole("default", "readRole");
} Defensive patterns
Strategy: validation
Validate before calling
boolean exists = getRoles("default").contains(roleName);
if (!exists) log.warn("Role absent, skipping delete: " + roleName); Try / catch
try {
client.deleteRole("default", roleName);
} catch (BasicSecurityDBResourceException e) {
if (e.getMessage().contains("does not exist")) {
log.info("Role {} already deleted", roleName);
} else { throw e; }
} Prevention
- Confirm role exists before delete
- Make teardown scripts tolerant of missing roles
- Use exact role names from a shared config, not hand-typed URLs
When it happens
Trigger: DELETE /druid-ext/basic-security/authorization/db/<authorizer>/roles/<roleName> where roleName is absent from the role map.
Common situations: Double-delete in cleanup scripts; role already removed by another admin; typo or wrong authorizer name in the URL; roles recreated under different names after a config migration.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Group mapping [%s] does not exist.
- User [%s] already exists.
- Group mapping [%s] already exists.
- Role [%s] already exists.
- User [%s] already has role [%s].
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/d2e6674d4e3fd908.
Report an issue: GitHub.