{"record":{"id":"23595a99079b8184","repo":"SonarSource/sonarqube","slug":"failed-to-fetch-azure-repository-url-for-alm-setti","errorCode":null,"errorMessage":"Failed to fetch Azure repository URL for ALM setting '{}', project '{}' and repository '{}'","messagePattern":"Failed to fetch Azure repository URL for ALM setting '(.+?)', project '(.+?)' and repository '(.+?)'","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GetBindingAction.java","lineNumber":207,"sourceCode":"        .build();\n      builder.setRepositoryUrl(repositoryUrl.toString());\n    }\n  }\n\n  private void setAzureRepositoryUrl(AlmSettingDto almSetting, ProjectAlmSettingDto projectAlmSetting, GetBindingWsResponse.Builder builder) {\n    if (isNotBlank(projectAlmSetting.getAlmSlug()) && isNotBlank(projectAlmSetting.getAlmRepo()) && isNotBlank(almSetting.getUrl())) {\n      try {\n        String personalAccessToken = almSetting.getDecryptedPersonalAccessToken(encryption);\n        if (isNotBlank(personalAccessToken)) {\n          GsonAzureRepo azureRepo = azureDevOpsHttpClient.getRepo(\n            requireNonNull(almSetting.getUrl()),\n            personalAccessToken,\n            requireNonNull(projectAlmSetting.getAlmSlug()),\n            requireNonNull(projectAlmSetting.getAlmRepo()));\n          builder.setRepositoryUrl(azureRepo.getWebUrl());\n        }\n      } catch (Exception e) {\n        LOG.warn(\"Failed to fetch Azure repository URL for ALM setting '{}', project '{}' and repository '{}'\",\n          almSetting.getKey(), projectAlmSetting.getAlmSlug(), projectAlmSetting.getAlmRepo(), e);\n      }\n    }\n  }\n\n  private static void setBitbucketServerRepositoryUrl(AlmSettingDto almSetting, ProjectAlmSettingDto projectAlmSetting,\n    GetBindingWsResponse.Builder builder) {\n    String serverUrl = almSetting.getUrl();\n    String bitbucketProjectKey = projectAlmSetting.getAlmRepo();\n    String repositorySlug = projectAlmSetting.getAlmSlug();\n    if (isNotBlank(serverUrl) && isNotBlank(bitbucketProjectKey) && isNotBlank(repositorySlug)) {\n      HttpUrl baseUrl = HttpUrl.parse(serverUrl);\n      if (baseUrl == null) {\n        LOG.warn(\"Failed to construct Bitbucket Server repository URL for ALM setting '{}': invalid server URL\", almSetting.getKey());\n        return;\n      }\n      builder.setRepositoryUrl(baseUrl.newBuilder()\n        .addPathSegment(\"projects\")","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GetBindingAction.java#L189-L225","documentation":"This warning is logged by GetBindingAction.setAzureRepositoryUrl when the Azure DevOps REST call to fetch the repository web URL fails. The code uses almSetting's URL, a personal access token, the stored almSlug (project) and almRepo (repository); any exception is swallowed and the binding response is returned without a repositoryUrl.","triggerScenarios":"GET api/alm_settings/get_binding on an Azure DevOps-bound project where the Azure API call fails: invalid/expired PAT, wrong organization URL, almSlug/almRepo not matching a real Azure project/repository, or network failure.","commonSituations":"Azure DevOps PAT expired (PATs have a max lifetime); repository renamed or deleted in Azure; project name changed; the Azure organization was renamed so the configured URL no longer resolves; typo in the project/repository slug.","solutions":["Refresh the Azure DevOps personal access token in the ALM setting (api/alm_settings/update_azure) ensuring Code Read scope","Verify almSlug and almRepo exactly match the Azure DevOps project and repository names, then re-bind with api/alm_settings/set_binding if not","Test the configured Azure URL and organization from the SonarQube host (check for renamed organization)","Inspect the attached stack trace/inner message in the log for the specific HTTP status returned by Azure"],"exampleFix":"// before: renamed repo\nalm_settings/set_binding?project=p&almSettingKey=azure1&almSlug=Proj&almRepo=old-repo\n// after\nalm_settings/set_binding?project=p&almSettingKey=azure1&almSlug=Proj&almRepo=renamed-repo","handlingStrategy":"try-catch","validationCode":"// Pre-flight: verify Azure PAT and repo before binding\ncurl -u \":<pat>\" \"https://dev.azure.com/<org>/<project>/_apis/git/repositories/<repo>?api-version=7.0\" # expect 200","typeGuard":null,"tryCatchPattern":"// Callers: degrade gracefully when repositoryUrl is absent\nif (!response.hasRepositoryUrl()) {\n  log.warn(\"Azure binding metadata unavailable; check PAT and repo slugs\");\n}","preventionTips":["Track Azure DevOps PAT expiration (max 1 year) and set rotation reminders","Re-validate slugs after any repo/project rename in Azure","Include Code Read scope in the PAT","Test ALM connectivity from the SonarQube host after org renames"],"tags":["alm-integration","azure-devops","network","authentication","logging"],"backgroundTag":"upstream-api-error","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"}