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

  1. Retry setPermissions after a delay.
  2. Restrict metadata writes to the elected coordinator leader.
  3. Serialize or batch permission updates.
  4. Increase numRetries for workloads with frequent concurrent updates.
  5. 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

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


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)