{"record":{"id":"4c21e7423518f5ed","repo":"apache/druid","slug":"user-s-does-not-exist-4c21e7","errorCode":null,"errorMessage":"User [%s] does not exist.","messagePattern":"User \\[(.+?)\\] does not exist\\.","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":872,"sourceCode":"      } else {\n        attempts++;\n      }\n      try {\n        Thread.sleep(ThreadLocalRandom.current().nextLong(UPDATE_RETRY_DELAY));\n      }\n      catch (InterruptedException ie) {\n        throw new RuntimeException(ie);\n      }\n    }\n    throw new ISE(\"Could not set permissions for role [%s] due to concurrent update contention.\", roleName);\n  }\n\n  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);","sourceCodeStart":854,"sourceCodeEnd":890,"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#L854-L890","documentation":"deleteUser checks the authorizer user map before removal; if the named user is absent from the map deserialized from metadata storage, it immediately throws BasicSecurityDBResourceException. This is a straightforward pre-condition failure: the delete target does not exist in the given authorizer's user map. Unlike the contention errors, no retries occur — the check happens on the first read.","triggerScenarios":"Calling deleteUser for a userName that was never created, was already deleted, or does not exist under the specified authorizer prefix (e.g. deleting from the wrong authorizer name).","commonSituations":"Double-delete in cleanup scripts without existence checks; typo'd or case-mismatched usernames; targeting the wrong authorizer (e.g. 'internal' vs a custom one); users removed concurrently by another admin between the check and prior calls.","solutions":["Check the user exists first (GET the user list for the authorizer) or treat BasicSecurityDBResourceException as an idempotent no-op.","Verify the authorizer prefix/name passed to deleteUser matches the one containing the user.","Confirm exact username spelling and case (the map is case-sensitive as stored).","Guard against double deletion in automation by tracking already-deleted users."],"exampleFix":"// before\nclient.deleteUser(authorizerPrefix, userName);\n// after: tolerate already-deleted\ntry {\n  client.deleteUser(authorizerPrefix, userName);\n} catch (BasicSecurityDBResourceException e) {\n  LOG.info(\"User [%s] already absent in [%s]; skipping.\", userName, authorizerPrefix);\n}","handlingStrategy":"try-catch","validationCode":"// Check existence before deleting\nMap<String, BasicAuthorizerUser> userMap = BasicAuthUtils.deserializeAuthorizerUserMap(\n    objectMapper, getCurrentUserMapBytes(prefix));\nif (!userMap.containsKey(userName)) {\n  LOG.info(\"User [%s] absent from [%s]; nothing to delete\", userName, prefix);\n  return;\n}","typeGuard":"boolean userExists(final String prefix, final String userName) {\n  return BasicAuthUtils.deserializeAuthorizerUserMap(\n      objectMapper, getCurrentUserMapBytes(prefix)).containsKey(userName);\n}","tryCatchPattern":"try {\n  updater.deleteUser(prefix, userName);\n} catch (BasicSecurityDBResourceException e) {\n  // idempotent delete: user already gone\n  LOG.info(\"User [%s] already absent in authorizer [%s].\", userName, prefix);\n}","preventionTips":["Make deletes idempotent by catching BasicSecurityDBResourceException","Verify the authorizer name/prefix before deleting","Match username spelling and case exactly","Avoid double-deletes in cleanup scripts by tracking processed users","Re-check user existence after concurrent admin operations"],"tags":["druid","basic-security","user-management","not-found"],"backgroundTag":"user-not-found","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"}