{"record":{"id":"b81f366d6b6e8c80","repo":"apache/druid","slug":"user-s-already-exists-b81f36","errorCode":null,"errorMessage":"User [%s] already exists.","messagePattern":"User \\[(.+?)\\] 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":885,"sourceCode":"  private boolean deleteUserOnce(String prefix, String userName)\n  {\n    byte[] oldValue = getCurrentUserMapBytes(prefix);\n    Map<String, BasicAuthorizerUser> userMap = BasicAuthUtils.deserializeAuthorizerUserMap(objectMapper, oldValue);\n    if (userMap.get(userName) == null) {\n      throw new BasicSecurityDBResourceException(\"User [%s] does not exist.\", userName);\n    } else {\n      userMap.remove(userName);\n    }\n    byte[] newValue = BasicAuthUtils.serializeAuthorizerUserMap(objectMapper, userMap);\n    return tryUpdateUserMap(prefix, userMap, oldValue, newValue);\n  }\n\n  private boolean createUserOnce(String prefix, String userName)\n  {\n    byte[] oldValue = getCurrentUserMapBytes(prefix);\n    Map<String, BasicAuthorizerUser> userMap = BasicAuthUtils.deserializeAuthorizerUserMap(objectMapper, oldValue);\n    if (userMap.get(userName) != null) {\n      throw new BasicSecurityDBResourceException(\"User [%s] already exists.\", userName);\n    } else {\n      userMap.put(userName, new BasicAuthorizerUser(userName, null));\n    }\n    byte[] newValue = BasicAuthUtils.serializeAuthorizerUserMap(objectMapper, userMap);\n    return tryUpdateUserMap(prefix, userMap, oldValue, newValue);\n  }\n\n  private boolean deleteGroupMappingOnce(String prefix, String groupMappingName)\n  {\n    byte[] oldValue = getCurrentGroupMappingMapBytes(prefix);\n    Map<String, BasicAuthorizerGroupMapping> groupMappingMap = BasicAuthUtils.deserializeAuthorizerGroupMappingMap(objectMapper, oldValue);\n    if (groupMappingMap.get(groupMappingName) == null) {\n      throw new BasicSecurityDBResourceException(\"Group mapping [%s] does not exist.\", groupMappingName);\n    } else {\n      groupMappingMap.remove(groupMappingName);\n    }\n    byte[] newValue = BasicAuthUtils.serializeAuthorizerGroupMappingMap(objectMapper, groupMappingMap);\n    return tryUpdateGroupMappingMap(prefix, groupMappingMap, oldValue, newValue);","sourceCodeStart":867,"sourceCodeEnd":903,"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#L867-L903","documentation":"BasicSecurityDBResourceException thrown by createUserOnce when a user with the requested name is already present in the coordinator's authorizer user map for the given authenticator/authorizer prefix. The coordinator does a read-check-update against the metadata store and refuses to create duplicate users because user names must be unique within an authorizer. Callers see it surfaced over HTTP as a 400-class response from the coordinator basic-security API.","triggerScenarios":"Calling POST /druid-ext/basic-security/authorization/db/<authorizer>/users/<userName> (or BasicAuthorizerResourceStorageUpdater client createUser) for a userName that already exists in that authorizer's user map.","commonSituations":"Automated user-provisioning scripts run twice without idempotency; re-running an init/bootstrap script that creates users; case/whitespace mismatches lead operators to think a user is new when it exists; migrating configs between clusters where the user already exists.","solutions":["Check existence first with GET /druid-ext/basic-security/authorization/db/<authorizer>/users/<userName> before creating","Make provisioning scripts idempotent: treat 'already exists' as success or use the update APIs instead of create","Verify you are targeting the intended authorizer prefix (e.g. default vs another authorizer name)","If the existing user is wrong, delete it via DELETE .../users/<userName> then recreate"],"exampleFix":"// before: blind create on every run\nclient.createUser(\"authentication\", \"default\", \"alice\");\n// after: idempotent create\nif (!userExists(\"default\", \"alice\")) {\n  client.createUser(\"authentication\", \"default\", \"alice\");\n}","handlingStrategy":"validation","validationCode":"boolean exists = client.getUser(\"default\", userName) != null;\nif (exists) throw new IllegalStateException(\"User already created: \" + userName);","typeGuard":null,"tryCatchPattern":"try {\n  client.createUser(\"default\", userName);\n} catch (BasicSecurityDBResourceException e) {\n  if (e.getMessage().contains(\"already exists\")) {\n    log.info(\"User {} already exists, skipping\", userName);\n  } else { throw e; }\n}","preventionTips":["Check existence with the GET endpoint before creating","Make all provisioning scripts idempotent","Use consistent, case-exact user names across environments","Verify the authorizer name in the URL before API calls"],"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"}