SonarSource/sonarqube · error · IllegalArgumentException

DevOps Platform ' ' is not supported by the Remediation…

Error message

DevOps Platform '%s' is not supported by the Remediation Agent

What it means

DopPermissionValidationService.check only supports GitHub, GitLab and Azure DevOps when checking whether the Remediation Agent may access a DevOps platform. BitBucket (server) and BitBucket Cloud configurations are explicitly rejected with this IllegalArgumentException. It is a deliberate unsupported-operation guard, not a configuration corruption.

Solutions

  1. Filter ALM settings to GITHUB/GITLAB/AZURE_DEVOPS before invoking the check
  2. Use a supported DevOps platform configuration for Remediation Agent checks
  3. Handle IllegalArgumentException per-setting so one unsupported integration doesn't fail a batch check

Example fix

// before
for (AlmSettingDto dto : almSettings) { results.add(service.check(dto)); }
// after
for (AlmSettingDto dto : almSettings) {
  if (dto.getAlm() == BITBUCKET || dto.getAlm() == BITBUCKET_CLOUD) continue;
  results.add(service.check(dto));
}
Defensive patterns

Strategy: type-guard

Validate before calling

Set<Alm> SUPPORTED = Set.of(GITHUB, GITLAB, AZURE_DEVOPS);
if (!SUPPORTED.contains(almSetting.getAlm())) throw new IllegalArgumentException("Remediation Agent unsupported: " + almSetting.getAlm());

Type guard

boolean isRemediationAgentSupported(AlmSettingDto dto) {
  return dto != null && EnumSet.of(GITHUB, GITLAB, AZURE_DEVOPS).contains(dto.getAlm());
}

Try / catch

try {
  check = service.check(almSetting);
} catch (IllegalArgumentException e) {
  // unsupported platform (BitBucket) — mark as N/A, not a failure
  check = DopPermissionCheck.unsupported(almSetting.getAlm());
}

Prevention

When it happens

Trigger: Calling the Remediation Agent permission check (via check()/result endpoint) with an AlmSettingDto whose alm() is BITBUCKET or BITBUCKET_CLOUD.

Common situations: Tenant configured BitBucket integration and then enabled/queried the Remediation Agent; API client iterates over all ALM settings including BitBucket without filtering by supported platform.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/47db4d8c627a47a8. Report an issue: GitHub.

Appendix: source

Thrown at server/sonar-webserver-common/src/main/java/org/sonar/server/common/almsettings/permission/DopPermissionValidationService.java:131

    GitlabGlobalSettingsValidator gitlabGlobalSettingsValidator, AzureDevOpsValidator azureDevOpsValidator, System2 system2, Ticker cacheTicker) {
    DopPermissionValidationService service = new DopPermissionValidationService(githubGlobalSettingsValidator, gitlabGlobalSettingsValidator,
      azureDevOpsValidator, system2);
    service.cache = buildCache(cacheTicker);
    return service;
  }

  /**
   * Checks the given DevOps Platform configuration against the Remediation Agent's required write permissions.
   *
   * @throws IllegalArgumentException if the configuration's platform is not supported (Bitbucket).
   */
  public DopPermissionCheck check(AlmSettingDto almSetting) {
    return switch (almSetting.getAlm()) {
      case GITHUB -> checkGithub(almSetting);
      case GITLAB -> checkGitlab(almSetting);
      case AZURE_DEVOPS -> checkAzure(almSetting);
      case BITBUCKET, BITBUCKET_CLOUD ->
        throw new IllegalArgumentException("DevOps Platform '" + almSetting.getAlm() + "' is not supported by the Remediation Agent");
    };
  }

  /**
   * Checks several configurations in parallel and returns the results in the same order as the input. Each individual
   * check is time-bounded by the ALM client's connect/read timeouts; running them concurrently keeps the total close to
   * the slowest single platform. Uses a virtual thread per check rather than a fixed pool — these calls are blocking
   * I/O, not CPU-bound, and there are at most a handful of supported platforms per instance, so there's no pool sizing
   * to tune and no thread reuse to lose by not sharing an executor across calls. All settings must be supported
   * platforms (see {@link #check(AlmSettingDto)}).
   */
  public List<DopPermissionCheck> checkAll(List<AlmSettingDto> almSettings) {
    return mapInParallel(almSettings, this::check);
  }

  /**
   * Cached counterpart to {@link #check(AlmSettingDto)}. A cache hit performs no external call. Concurrent misses for
   * the same configuration are coalesced into a single live check (Guava {@code Cache.get(key, Callable)} semantics).

View on GitHub (pinned to 184c821202)