apache/druid · error · BasicSecurityDBResourceException
Group mapping [%s] already exists.
Error message
Group mapping [%s] already exists.
What it means
BasicSecurityDBResourceException thrown by createGroupMappingOnce when a group mapping with the same name already exists in the authorizer's group-mapping map. Group mapping names are unique keys, so the coordinator rejects duplicate creation rather than overwriting existing permissions. Prevents silently replacing an LDAP group-to-role mapping.
Source
Thrown at extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/db/updater/CoordinatorBasicAuthorizerMetadataStorageUpdater.java:911
private boolean deleteGroupMappingOnce(String prefix, String groupMappingName)
{
byte[] oldValue = getCurrentGroupMappingMapBytes(prefix);
Map<String, BasicAuthorizerGroupMapping> groupMappingMap = BasicAuthUtils.deserializeAuthorizerGroupMappingMap(objectMapper, oldValue);
if (groupMappingMap.get(groupMappingName) == null) {
throw new BasicSecurityDBResourceException("Group mapping [%s] does not exist.", groupMappingName);
} else {
groupMappingMap.remove(groupMappingName);
}
byte[] newValue = BasicAuthUtils.serializeAuthorizerGroupMappingMap(objectMapper, groupMappingMap);
return tryUpdateGroupMappingMap(prefix, groupMappingMap, oldValue, newValue);
}
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);View on GitHub (pinned to 9b90983fd2)
Solutions
- Check GET /druid-ext/basic-security/authorization/db/<authorizer>/groupMappings/<name> before creating
- To change an existing mapping, use the PUT/update endpoint rather than create
- Make setup scripts idempotent by skipping existing mappings
- Delete the existing mapping first if a clean re-create is truly intended
Example fix
// before
createGroupMapping("default", mapping); // fails if exists
// after
if (groupMappingExists("default", mapping.getName())) {
updateGroupMapping("default", mapping.getName(), mapping);
} else {
createGroupMapping("default", mapping);
} Defensive patterns
Strategy: validation
Validate before calling
boolean exists = getGroupMappings("default").stream()
.anyMatch(gm -> gm.equals(mapping.getName()));
if (exists) { update instead of create } Try / catch
try {
client.createGroupMapping("default", mapping);
} catch (BasicSecurityDBResourceException e) {
if (e.getMessage().contains("already exists")) {
client.updateGroupMapping("default", mapping.getName(), mapping);
} else { throw e; }
} Prevention
- Check existence before create; prefer update semantics for re-runs
- Store group mapping definitions in config management for idempotency
- Use distinct names per environment to avoid collisions
When it happens
Trigger: POST /druid-ext/basic-security/authorization/db/<authorizer>/groupMappings/<groupMappingName> with a name that already exists in that authorizer.
Common situations: Re-running a setup script that defines LDAP group mappings; copying mappings between clusters where the name already exists; wanting to change a mapping but calling create instead of update.
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.
- Role [%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/2272d2dbef914de2.
Report an issue: GitHub.