{"record":{"id":"222a406a30ed2990","repo":"apache/druid","slug":"could-not-create-group-mapping-s-due-to-concurr","errorCode":null,"errorMessage":"Could not create group mapping [%s] due to concurrent update contention.","messagePattern":"Could not create group mapping \\[(.+?)\\] due to concurrent update contention\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":500,"severity":"error","filePath":"extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/db/updater/CoordinatorBasicAuthorizerMetadataStorageUpdater.java","lineNumber":707,"sourceCode":"  }\n\n  private void createGroupMappingInternal(String prefix, BasicAuthorizerGroupMapping groupMapping)\n  {\n    int attempts = 0;\n    while (attempts < numRetries) {\n      if (createGroupMappingOnce(prefix, groupMapping)) {\n        return;\n      } 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 create group mapping [%s] due to concurrent update contention.\", groupMapping);\n  }\n\n  private void deleteGroupMappingInternal(String prefix, String groupMappingName)\n  {\n    int attempts = 0;\n    while (attempts < numRetries) {\n      if (deleteGroupMappingOnce(prefix, groupMappingName)) {\n        return;\n      } 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    }","sourceCodeStart":689,"sourceCodeEnd":725,"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#L689-L725","documentation":"The coordinator-side basic authorizer metadata storage updater failed to create an authorization group mapping after exhausting all CAS retry attempts (numRetries). Each attempt re-reads the group mapping map from metadata storage and does a compare-and-swap update; if another writer keeps winning the race, the retries run out and this ISE is thrown. It signals persistent concurrent update contention on the group mapping map in metadata storage, not a validation problem with the mapping itself.","triggerScenarios":"Calling createGroupMapping (or startup via initSuperUsersAndGroupMapping) while another process keeps updating the same authorizer prefix's group mapping map so every tryUpdateGroupMappingMap compare-and-swap fails for numRetries consecutive attempts.","commonSituations":"Multiple coordinator overlord/leader instances concurrently mutating basic-security authorization entities; automation scripts or CI repeatedly creating the same group mapping in parallel; a hot metadata store (e.g. slow/contended ZooKeeper or metadata store) making each CAS retry fail; unusually low numRetries configuration under bursty admin traffic.","solutions":["Retry the createGroupMapping call after a delay; the failure is contention-based, so a subsequent attempt usually succeeds.","Verify only one coordinator is acting as leader/performing metadata writes for this authorizer at a time.","Reduce write concurrency: serialize admin/automation requests against the basic security API for this authorizer prefix.","Increase the updater's retry budget (numRetries) if bursts of concurrent updates are expected.","Inspect metadata storage latency/health; slow CAS operations widen the contention window."],"exampleFix":"// before: fire-and-forget parallel setup\nusers.forEach(u -> client.createGroupMapping(prefix, u));\n// after: serialize mutations with bounded retry\nfor (final String u : users) {\n  boolean ok = retryUntil(() -> { try { client.createGroupMapping(prefix, u); return true; }\n                            catch (ISE e) { return false; } }, 5);\n  if (!ok) throw new IllegalStateException(\"group mapping \" + u + \" still contended\");\n}","handlingStrategy":"retry","validationCode":"// Verify no concurrent writers before mutating\nboolean isLeader = coordinatorClient.isCurrentLeader();\nif (!isLeader) throw new IllegalStateException(\"Not the leader; skip metadata writes\");","typeGuard":null,"tryCatchPattern":"try {\n  updater.createGroupMapping(prefix, groupMapping);\n} catch (IJSE e) {\n  // contention exhausted; back off and retry once\n  Thread.sleep(RETRY_BACKOFF_MS);\n  updater.createGroupMapping(prefix, groupMapping);\n}","preventionTips":["Only the leader coordinator should write basic-security metadata","Serialize admin mutations; avoid parallel provisioning scripts","Use randomized backoff between attempts","Increase numRetries for bursty workloads","Monitor metadata store latency to shrink the contention window"],"tags":["druid","basic-security","zookeeper","concurrency"],"backgroundTag":"concurrent-update-contention","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"}