{"record":{"id":"330568432d4b32d7","repo":"SonarSource/sonarqube","slug":"gitlab-configuration-already-exists-only-one-gitl","errorCode":null,"errorMessage":"GitLab configuration already exists. Only one Gitlab configuration is supported.","messagePattern":"GitLab configuration already exists\\. Only one Gitlab configuration is supported\\.","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"server/sonar-webserver-common/src/main/java/org/sonar/server/common/gitlab/config/GitlabConfigurationService.java","lineNumber":243,"sourceCode":"      setProperty(dbSession, GITLAB_AUTH_ALLOWED_GROUPS, String.join(\",\", configuration.allowedGroups()));\n      setProperty(dbSession, GITLAB_AUTH_ALLOW_ALL_GROUPS, String.valueOf(configuration.allowAllGroups()));\n      setProperty(dbSession, GITLAB_AUTH_PROVISIONING_ENABLED, String.valueOf(enableAutoProvisioning));\n      setProperty(dbSession, GITLAB_AUTH_ALLOW_USERS_TO_SIGNUP, String.valueOf(configuration.allowUsersToSignUp()));\n      setProperty(dbSession, GITLAB_AUTH_PROVISIONING_TOKEN, configuration.provisioningToken());\n      if (enableAutoProvisioning) {\n        triggerRun(configuration);\n      }\n      GitlabConfiguration createdConfiguration = getConfiguration(UNIQUE_GITLAB_CONFIGURATION_ID, dbSession);\n      dbSession.commit();\n      return createdConfiguration;\n    }\n\n  }\n\n  private void throwIfConfigurationAlreadyExists() {\n    Optional.ofNullable(dbClient.propertiesDao().selectGlobalProperty(GITLAB_AUTH_ENABLED)).ifPresent(property -> {\n      throw BadRequestException.create(\"GitLab configuration already exists. Only one Gitlab configuration is supported.\");\n    });\n  }\n\n  private static void throwIfInvalidAllowedGroupConfigurationAndAutoProvisioning(ProvisioningType provisioningType, Set<String> allowedGroups, boolean allowAllGroups) {\n    if (provisioningType == AUTO_PROVISIONING && allowedGroups.isEmpty() && !allowAllGroups) {\n      throw new IllegalArgumentException(\"allowedGroups cannot be empty when Auto-provisioning is enabled and allowAllGroups is set to false.\");\n    }\n  }\n\n  private static void throwIfAllowAllGroupsAndJit(ProvisioningType provisioningType, boolean allowAllGroups) {\n    if (allowAllGroups && provisioningType != AUTO_PROVISIONING) {\n      throw new IllegalArgumentException(\"allowAllGroups can only be enabled when Auto-provisioning is enabled.\");\n    }\n  }\n\n  private static void throwIfAllowAllGroupsAndGitlabCloud(String url, boolean allowAllGroups) {\n    if (allowAllGroups && isGitlabCloudUrl(url)) {\n      throw new IllegalArgumentException(\n        \"allowAllGroups cannot be enabled when the GitLab URL is gitlab.com (GitLab SaaS). \"","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-common/src/main/java/org/sonar/server/common/gitlab/config/GitlabConfigurationService.java#L225-L261","documentation":"GitlabConfigurationService allows only one GitLab configuration. throwIfConfigurationAlreadyExists checks for an existing GITLAB_AUTH_ENABLED global property; if present, createConfiguration aborts with BadRequestException (HTTP 400) saying only one configuration is supported. This prevents duplicate/conflicting GitLab global configs.","triggerScenarios":"POST/createConfiguration called when a GitLab configuration already exists (GITLAB_AUTH_ENABLED global property set) — e.g. double-clicking save, re-running an idempotent-unaware Terraform/script, or creating GitLab config after migration from ALM settings.","commonSituations":"Infrastructure-as-code re-apply without existence check; two admins configuring GitLab simultaneously; automation that creates instead of updates.","solutions":["Check existence first (getConfiguration) and call updateConfiguration instead of createConfiguration","Catch the 400 BadRequestException and fall back to an update flow","Make IaC/scripts idempotent: create only if the GitLab config API returns 404","Remove the existing GitLab configuration first if a clean re-create is intended"],"exampleFix":"// before\nservice.createConfiguration(cfg); // 400 if already exists\n// after\ntry { service.createConfiguration(cfg); }\ncatch (BadRequestException e) { service.updateConfiguration(UNIQUE_GITLAB_CONFIGURATION_ID, cfg); }","handlingStrategy":"try-catch","validationCode":"// upsert pattern\nboolean exists;\ntry { client.getGitlabConfiguration(); exists = true; }\ncatch (NotFoundException e) { exists = false; }\nif (exists) client.updateGitlabConfiguration(cfg); else client.createGitlabConfiguration(cfg);","typeGuard":null,"tryCatchPattern":"try {\n  service.createConfiguration(cfg);\n} catch (BadRequestException e) {\n  // already exists — switch to update instead of failing\n  service.updateConfiguration(UNIQUE_GITLAB_CONFIGURATION_ID, cfg);\n}","preventionTips":["Make IaC/automation idempotent: read-modify-write instead of blind create","Guard create endpoints in scripts with a prior existence check","Serialize configuration changes to avoid concurrent duplicate creates"],"tags":["gitlab","configuration","duplicate","bad-request"],"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-17T15:17:12.973Z"}