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,
        oldGroupMapValue

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Confirm the role exists with GET /druid-ext/basic-security/authorization/db/<authorizer>/roles before deleting
  2. Make deletion idempotent in scripts by tolerating 'does not exist'
  3. Verify the authorizer name in the request path
  4. 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

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


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/d2e6674d4e3fd908. Report an issue: GitHub.