{"record":{"id":"2be0d4980b3583b4","repo":"apache/druid","slug":"role-s-already-exists","errorCode":null,"errorMessage":"Role [%s] already exists.","messagePattern":"Role \\[(.+?)\\] already exists\\.","errorType":"http","errorClass":"BasicSecurityDBResourceException","httpStatus":400,"severity":"error","filePath":"extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/db/updater/CoordinatorBasicAuthorizerMetadataStorageUpdater.java","lineNumber":924,"sourceCode":"  private boolean createGroupMappingOnce(String prefix, BasicAuthorizerGroupMapping groupMapping)\n  {\n    byte[] oldValue = getCurrentGroupMappingMapBytes(prefix);\n    Map<String, BasicAuthorizerGroupMapping> groupMappingMap = BasicAuthUtils.deserializeAuthorizerGroupMappingMap(objectMapper, oldValue);\n    if (groupMappingMap.get(groupMapping.getName()) != null) {\n      throw new BasicSecurityDBResourceException(\"Group mapping [%s] already exists.\", groupMapping.getName());\n    } else {\n      groupMappingMap.put(groupMapping.getName(), groupMapping);\n    }\n    byte[] newValue = BasicAuthUtils.serializeAuthorizerGroupMappingMap(objectMapper, groupMappingMap);\n    return tryUpdateGroupMappingMap(prefix, groupMappingMap, oldValue, newValue);\n  }\n\n  private boolean createRoleOnce(String prefix, String roleName)\n  {\n    byte[] oldValue = getCurrentRoleMapBytes(prefix);\n    Map<String, BasicAuthorizerRole> roleMap = BasicAuthUtils.deserializeAuthorizerRoleMap(objectMapper, oldValue);\n    if (roleMap.get(roleName) != null) {\n      throw new BasicSecurityDBResourceException(\"Role [%s] already exists.\", roleName);\n    } else {\n      roleMap.put(roleName, new BasicAuthorizerRole(roleName, null));\n    }\n    byte[] newValue = BasicAuthUtils.serializeAuthorizerRoleMap(objectMapper, roleMap);\n    return tryUpdateRoleMap(prefix, roleMap, oldValue, newValue);\n  }\n\n  private boolean deleteRoleOnce(String prefix, String roleName)\n  {\n    byte[] oldRoleMapValue = getCurrentRoleMapBytes(prefix);\n    Map<String, BasicAuthorizerRole> roleMap = BasicAuthUtils.deserializeAuthorizerRoleMap(\n        objectMapper,\n        oldRoleMapValue\n    );\n    if (roleMap.get(roleName) == null) {\n      throw new BasicSecurityDBResourceException(\"Role [%s] does not exist.\", roleName);\n    } else {\n      roleMap.remove(roleName);","sourceCodeStart":906,"sourceCodeEnd":942,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/db/updater/CoordinatorBasicAuthorizerMetadataStorageUpdater.java#L906-L942","documentation":"BasicSecurityDBResourceException thrown by createRoleOnce when a role with the requested name already exists in the authorizer's role map. Role names are unique within an authorizer, and the coordinator refuses to create duplicates so existing permissions are never silently overwritten. It is a client-input/validation error surfaced via the coordinator API.","triggerScenarios":"POST /druid-ext/basic-security/authorization/db/<authorizer>/roles/<roleName> for a role that already exists.","commonSituations":"Idempotency issues in provisioning scripts that define roles; re-importing a role export that already exists; multiple admins creating the same role concurrently; calling create when the intent was to update the role's permissions.","solutions":["Check role existence via GET /druid-ext/basic-security/authorization/db/<authorizer>/roles/<roleName> first","Use the update API to modify permissions of an existing role instead of create","Skip creation when the role already exists in automation scripts","Delete the existing role (checking user assignments first) if a fresh role is required"],"exampleFix":"// before\ncreateRole(\"default\", \"readRole\");\n// after\nif (!roleExists(\"default\", \"readRole\")) {\n  createRole(\"default\", \"readRole\");\n}","handlingStrategy":"validation","validationCode":"boolean exists = getRoles(\"default\").stream()\n    .anyMatch(r -> r.equals(roleName));\nif (exists) skipCreation(roleName);","typeGuard":null,"tryCatchPattern":"try {\n  client.createRole(\"default\", roleName);\n} catch (BasicSecurityDBResourceException e) {\n  if (e.getMessage().contains(\"already exists\")) {\n    log.info(\"Role {} already exists\", roleName);\n  } else { throw e; }\n}","preventionTips":["Check role existence via GET before creating","Use the update endpoint to change permissions of existing roles","Sequence role creation before user/role assignments in scripts"],"tags":["security","rest-api","duplicate-resource"],"backgroundTag":"file-already-exists","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}