apache/druid · error · IllegalStateException
Could not set permissions for role
Error message
Could not set permissions for role [%s] due to concurrent update contention.
What it means
Setting permissions for a basic authorizer role failed after all numRetries compare-and-swap attempts were beaten by concurrent writers of the role metadata. The updater re-reads the role, re-applies the permission list, and retries with randomized delay before throwing this ISE naming the role. It signals persistent contention on the authorizer metadata store.
Solutions
- Retry setPermissions after a delay.
- Restrict metadata writes to the elected coordinator leader.
- Serialize or batch permission updates.
- Increase numRetries for workloads with frequent concurrent updates.
- Check metadata storage latency and load.
Example fix
// before
roles.forEach(r -> client.setPermissions(prefix, r, perms));
// after: serialized with retry
for (final String r : roles) {
RetryUtils.retry(() -> client.setPermissions(prefix, r, perms),
e -> e instanceof IllegalStateException, MAX_ATTEMPTS);
} Defensive patterns
Strategy: retry
Validate before calling
// Confirm role exists before setting permissions
Map<String, BasicAuthorizerRole> roles =
BasicAuthUtils.deserializeAuthorizerRoleMap(mapper, getCurrentRoleMapBytes(prefix));
if (!roles.containsKey(roleName)) throw new IllegalArgumentException("role missing"); Try / catch
try {
updater.setPermissions(prefix, roleName, permissions);
} catch (IJSE e) {
RetryUtils.retry(() -> updater.setPermissions(prefix, roleName, permissions),
ex -> ex instanceof IllegalStateException, MAX_ATTEMPTS);
} Prevention
- Batch/serialize permission updates
- Leader-only metadata writes
- Randomized backoff on retries
- Raise numRetries for concurrent admin traffic
- Track metadata store latency
When it happens
Trigger: Calling setPermissions while other writers repeatedly update roles/users/group mappings for the same authorizer prefix so every tryUpdateGroupMappingMap CAS fails through all retries.
Common situations: Bulk permission reconfiguration run in parallel across workers; permission updates racing with user-role assignments; multiple coordinators writing concurrently.
Related errors
- Could not assign role
- Could not assign role
- Could not create group mapping
- Could not create role
- Could not delete group mapping
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/3a58ec7ed31d67cf.
Report an issue: GitHub.
Appendix: source
Thrown at extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/db/updater/CoordinatorBasicAuthorizerMetadataStorageUpdater.java:864
}
private void setPermissionsInternal(String prefix, String roleName, List<ResourceAction> permissions)
{
int attempts = 0;
while (attempts < numRetries) {
if (setPermissionsOnce(prefix, roleName, permissions)) {
return;
} 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);View on GitHub (pinned to 9b90983fd2)