{"record":{"id":"9395ee61ce92d54f","repo":"SonarSource/sonarqube","slug":"an-devops-platform-setting-with-key-s-already-e","errorCode":null,"errorMessage":"An DevOps Platform setting with key '%s' already exists","messagePattern":"An DevOps Platform setting with key '(.+?)' already exists","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/AlmSettingsSupport.java","lineNumber":86,"sourceCode":"  // persisting more than one ALM setting per family.\n  private final ReentrantLock almSettingCreationLock = new ReentrantLock();\n\n  public AlmSettingsSupport(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder,\n    MultipleAlmFeature multipleAlmFeature) {\n    this.dbClient = dbClient;\n    this.userSession = userSession;\n    this.componentFinder = componentFinder;\n    this.multipleAlmFeature = multipleAlmFeature;\n  }\n\n  DbClient getDbClient() {\n    return dbClient;\n  }\n\n  public void checkAlmSettingDoesNotAlreadyExist(DbSession dbSession, String almSetting) {\n    dbClient.almSettingDao().selectByKey(dbSession, almSetting)\n      .ifPresent(a -> {\n        throw new IllegalArgumentException(format(\"An DevOps Platform setting with key '%s' already exists\", a.getKey()));\n      });\n  }\n\n  public void checkAlmMultipleFeatureEnabled(DbSession dbSession, ALM alm) {\n    if (!multipleAlmFeature.isAvailable() && !dbClient.almSettingDao().selectByAlm(dbSession, alm).isEmpty()) {\n      throw BadRequestException.create(\"A \" + alm + \" setting is already defined\");\n    }\n  }\n\n  /**\n   * Wraps an ALM setting creation in the JVM-wide lock that guarantees the check-then-insert\n   * of {@link #checkAlmMultipleFeatureEnabled(DbSession, ALM)} is atomic. Callers must commit\n   * inside the lambda so the row is visible before the lock is released. Enterprise/Data Center\n   * editions still take the lock — the count check inside is a no-op there, so contention is\n   * limited to admin ALM setup, which is rare.\n   */\n  public void withAlmSettingCreationLock(Runnable action) {\n    almSettingCreationLock.lock();","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/AlmSettingsSupport.java#L68-L104","documentation":"IllegalArgumentException from AlmSettingsSupport.checkAlmSettingDoesNotAlreadyExist, thrown by all create*Setting WS handlers when an ALM setting with the same key already exists in ALM_SETTINGS. Keys are unique identifiers for DevOps Platform configurations.","triggerScenarios":"POST api/alm_settings/create_azure|create_gitlab|create_bitbucket|create_bitbucketcloud|create_github with a key that already exists in the table.","commonSituations":"Re-running an infrastructure-as-code script without unique keys; re-creating a config after a partial delete; name collisions between teams.","solutions":["Choose a different, unique key for the new configuration","Delete or update the existing setting instead of creating a duplicate","If updating is intended, call the update_alm_settings endpoint rather than create"],"exampleFix":"// before\nPOST /api/alm_settings/create_github key=github (already exists)\n// after\nPOST /api/alm_settings/create_github key=github-team-a","handlingStrategy":"validation","validationCode":"const list = await ws.get('api/alm_settings/list');\nif (list.almSettings.some(s => s.key === newKey)) {\n  throw new Error(`Key '${newKey}' already exists; pick another or update the existing setting`);\n}","typeGuard":"const keyIsFree = (list, key) => !list.almSettings.some(s => s.key === key);","tryCatchPattern":"try {\n  await ws.post('api/alm_settings/create_github', {key, url});\n} catch (e) {\n  if (e.status === 400 && /already exists/.test(e.message)) {\n    await ws.post('api/alm_settings/update_github', {key, url}); // idempotent path\n  } else { throw e; }\n}","preventionTips":["Generate unique keys (team/env suffix) in IaC templates","Make creation idempotent: check-then-create or update-on-conflict","Use update endpoints for reconfiguration instead of create"],"tags":["sonarqube","webapi","duplicate-key"],"backgroundTag":"file-already-exists","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}