apache/druid · error · BasicSecurityDBResourceException
User [%s] does not exist.
Error message
User [%s] does not exist.
What it means
deleteUser checks the authorizer user map before removal; if the named user is absent from the map deserialized from metadata storage, it immediately throws BasicSecurityDBResourceException. This is a straightforward pre-condition failure: the delete target does not exist in the given authorizer's user map. Unlike the contention errors, no retries occur — the check happens on the first read.
Source
Thrown at extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/db/updater/CoordinatorBasicAuthorizerMetadataStorageUpdater.java:872
} else {
attempts++;
}
try {
Thread.sleep(ThreadLocalRandom.current().nextLong(UPDATE_RETRY_DELAY));
}
catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
}
throw new ISE("Could not set permissions for role [%s] due to concurrent update contention.", roleName);
}
private boolean deleteUserOnce(String prefix, String userName)
{
byte[] oldValue = getCurrentUserMapBytes(prefix);
Map<String, BasicAuthorizerUser> userMap = BasicAuthUtils.deserializeAuthorizerUserMap(objectMapper, oldValue);
if (userMap.get(userName) == null) {
throw new BasicSecurityDBResourceException("User [%s] does not exist.", userName);
} else {
userMap.remove(userName);
}
byte[] newValue = BasicAuthUtils.serializeAuthorizerUserMap(objectMapper, userMap);
return tryUpdateUserMap(prefix, userMap, oldValue, newValue);
}
private boolean createUserOnce(String prefix, String userName)
{
byte[] oldValue = getCurrentUserMapBytes(prefix);
Map<String, BasicAuthorizerUser> userMap = BasicAuthUtils.deserializeAuthorizerUserMap(objectMapper, oldValue);
if (userMap.get(userName) != null) {
throw new BasicSecurityDBResourceException("User [%s] already exists.", userName);
} else {
userMap.put(userName, new BasicAuthorizerUser(userName, null));
}
byte[] newValue = BasicAuthUtils.serializeAuthorizerUserMap(objectMapper, userMap);
return tryUpdateUserMap(prefix, userMap, oldValue, newValue);View on GitHub (pinned to 9b90983fd2)
Solutions
- Check the user exists first (GET the user list for the authorizer) or treat BasicSecurityDBResourceException as an idempotent no-op.
- Verify the authorizer prefix/name passed to deleteUser matches the one containing the user.
- Confirm exact username spelling and case (the map is case-sensitive as stored).
- Guard against double deletion in automation by tracking already-deleted users.
Example fix
// before
client.deleteUser(authorizerPrefix, userName);
// after: tolerate already-deleted
try {
client.deleteUser(authorizerPrefix, userName);
} catch (BasicSecurityDBResourceException e) {
LOG.info("User [%s] already absent in [%s]; skipping.", userName, authorizerPrefix);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Check existence before deleting
Map<String, BasicAuthorizerUser> userMap = BasicAuthUtils.deserializeAuthorizerUserMap(
objectMapper, getCurrentUserMapBytes(prefix));
if (!userMap.containsKey(userName)) {
LOG.info("User [%s] absent from [%s]; nothing to delete", userName, prefix);
return;
} Type guard
boolean userExists(final String prefix, final String userName) {
return BasicAuthUtils.deserializeAuthorizerUserMap(
objectMapper, getCurrentUserMapBytes(prefix)).containsKey(userName);
} Try / catch
try {
updater.deleteUser(prefix, userName);
} catch (BasicSecurityDBResourceException e) {
// idempotent delete: user already gone
LOG.info("User [%s] already absent in authorizer [%s].", userName, prefix);
} Prevention
- Make deletes idempotent by catching BasicSecurityDBResourceException
- Verify the authorizer name/prefix before deleting
- Match username spelling and case exactly
- Avoid double-deletes in cleanup scripts by tracking processed users
- Re-check user existence after concurrent admin operations
When it happens
Trigger: Calling deleteUser for a userName that was never created, was already deleted, or does not exist under the specified authorizer prefix (e.g. deleting from the wrong authorizer name).
Common situations: Double-delete in cleanup scripts without existence checks; typo'd or case-mismatched usernames; targeting the wrong authorizer (e.g. 'internal' vs a custom one); users removed concurrently by another admin between the check and prior calls.
Understand the failure class
Background: "User not found", "Invalid user", and "does not exist": what missing-user lookup errors mean across Rocket.Chat, LiteLLM, Phabricator, rustfs, and pnpm — this error's family across 10 libraries.
Related errors
- User [%s] already exists.
- User [%s] does not exist.
- Could not create group mapping [%s] due to concurrent update
- Could not delete group mapping [%s] due to concurrent update
- Could not create role [%s] due to concurrent update contenti
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/4c21e7423518f5ed.
Report an issue: GitHub.