SonarSource/sonarqube · warning
Failed to resolve url/repoId for DevOps Platform binding '{}
Error message
Failed to resolve url/repoId for DevOps Platform binding '{}': {} ({}) What it means
This warning is logged by ProjectBindingsServiceServerImpl.resolveLive when live resolution of a binding's repository URL and repoId from the ALM REST API fails. The method returns an empty LiveResolution so the search continues; only the sanitized message and exception class name are logged because ALM client exceptions can embed externally-influenced data in their message chains (log-injection risk).
Source
Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/ProjectBindingsServiceServerImpl.java:258
dbSession.rollback();
}
}
private LiveResolution resolveLive(AlmSettingDto almSetting, ProjectAlmSettingDto projectAlmSetting, Map<String, String> bitbucketCloudTokenCache) {
try {
return switch (almSetting.getAlm()) {
case GITHUB -> resolveGithub(almSetting, projectAlmSetting);
case GITLAB -> resolveGitlab(almSetting, projectAlmSetting);
case AZURE_DEVOPS -> resolveAzure(almSetting, projectAlmSetting);
case BITBUCKET -> resolveBitbucketServer(almSetting, projectAlmSetting);
case BITBUCKET_CLOUD -> resolveBitbucketCloud(almSetting, projectAlmSetting, bitbucketCloudTokenCache);
};
} catch (Exception e) {
// Never logs "e" directly: exceptions thrown by the ALM REST clients themselves (not just this class) can
// embed raw, externally-influenced data (an ALM-side error response body, a repository identifier) in their
// message chain — logging the throwable as-is would re-open the same CRLF log-injection issue that
// sanitizeForLog exists to close, just one layer down, in code this class doesn't control.
LOG.warn("Failed to resolve url/repoId for DevOps Platform binding '{}': {} ({})", projectAlmSetting.getUuid(),
sanitizeForLog(String.valueOf(e.getMessage())), e.getClass().getSimpleName());
return new LiveResolution("", "");
}
}
private LiveResolution resolveGithub(AlmSettingDto almSetting, ProjectAlmSettingDto projectAlmSetting) {
String almRepo = requireNonNull(projectAlmSetting.getAlmRepo(), ALM_REPO_CANNOT_BE_NULL);
String safeAlmRepo = sanitizeForLog(almRepo);
String url = requireNonNull(almSetting.getUrl(), URL_CANNOT_BE_NULL);
GithubAppConfiguration githubAppConfiguration = githubGlobalSettingsValidator.validate(almSetting);
long installationId = githubApplicationClient.getInstallationId(githubAppConfiguration, almRepo)
.orElseThrow(() -> new IllegalStateException(format("GitHub App is not installed on repository '%s'", safeAlmRepo)));
AppInstallationToken accessToken = githubApplicationClient.createAppInstallationToken(githubAppConfiguration, installationId, bareRepositoryName(almRepo))
.orElseThrow(() -> new IllegalStateException(format("Failed to create a GitHub App installation token for repository '%s'", safeAlmRepo)));
GithubApplicationClient.Repository repository = githubApplicationClient.getRepository(url, accessToken, almRepo)
.orElseThrow(() -> new IllegalStateException(format("Repository '%s' not found on GitHub", safeAlmRepo)));
String repoUrl = requireNonNull(repository.getUrl(), format("GitHub returned no url for repository '%s'", safeAlmRepo));
return new LiveResolution(repoUrl, Long.toString(repository.getId()));View on GitHub (pinned to 184c821202)
Solutions
- Check the logged exception class/message to identify the failing ALM and error type (IO vs HTTP vs parse)
- Validate the ALM setting's URL and credentials from the SonarQube host (curl the ALM API with the configured token)
- Re-bind the affected project if repository identifiers changed (api/alm_settings/set_binding)
- Retry the search — resolution is transient-cached; once the ALM is reachable the url/repoId are persisted via the persist path
Example fix
// before: unreachable ALM Failed to resolve url/repoId ... (SocketTimeoutException) // after fixing connectivity curl https://alm.example.com/api/v3/rate_limit -H 'Authorization: token <PAT>' → 200, bindings resolve
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight ALM reachability before heavy resolution
boolean reachable = pingAlm(almSetting.getUrl()); // HTTP probe with short timeout
if (!reachable) throw new IllegalStateException("ALM unreachable: " + almSetting.getUrl()); Try / catch
// Same resilient pattern the code uses: fall back to empty resolution
try { return resolveFromAlm(almSetting, binding); }
catch (Exception e) { log.warn("resolve failed: {} ({})", sanitize(e.getMessage()), e.getClass().getSimpleName()); return new LiveResolution("", ""); } Prevention
- Monitor egress connectivity and TLS trust to ALM hosts from the SonarQube host
- Rotate ALM credentials before expiry
- Handle ALM rate limits with backoff on the client side
- Treat empty LiveResolution as a cache miss and retry later
When it happens
Trigger: api/project_bindings/search (or resolveUrlAndRepoId) where the ALM client call for GitHub/GitLab/Azure/Bitbucket fails: unreachable ALM host, invalid credentials, wrong repository identifiers, rate limits, or malformed ALM responses.
Common situations: Firewall change blocking egress to the ALM; expired PAT/app credential; repository renamed; ALM returning 5xx or non-JSON bodies; self-signed certificates failing TLS validation.
Related errors
- Failed to fetch GitLab repository URL for ALM setting '{}' a
- Failed to fetch Azure repository URL for ALM setting '{}', p
- Skipping project binding '{}' from search results: failed to
- Failed to construct GitHub repository URL for ALM setting '{
- Skipping GitHub authentication setup: {}
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/b58779efb3591fa4.
Report an issue: GitHub.