SonarSource/sonarqube · error · IllegalArgumentException

is not a valid url

Error message

%s is not a valid url

What it means

GenericApplicationHttpClient.toAbsoluteEndPoint builds an absolute URL from the ALM host plus a relative endpoint, and throws IllegalArgumentException when the concatenated host+endpoint cannot be parsed as a valid URI/URL. The failing value is reported in the message so the misconfigured input can be identified. It guards any devops-platform integration (Azure DevOps, GitHub, etc.) backed by this generic client.

Solutions

  1. Fix the ALM platform URL in SonarQube project administration settings to include scheme and no illegal characters (e.g. https://server.example.com).
  2. URL-encode or remove special characters (spaces, #, %) from host and endpoint values.
  3. Verify the host setting is non-empty in sonar.properties / alm settings before saving.
  4. Escape the failing value from the message with new URI(host + endPoint) locally to pinpoint the illegal character.

Example fix

// before (settings UI)
almsettingazure=devops.company.com

// after
almsettingazure=https://devops.company.com
Defensive patterns

Strategy: validation

Validate before calling

static boolean isValidAlmUrl(String host, String endpoint) {
  String candidate = endpoint != null && endpoint.startsWith("http") ? endpoint : host + endpoint;
  try {
    new URI(candidate).toURL();
    return true;
  } catch (URISyntaxException | IllegalArgumentException | MalformedURLException e) {
    return false;
  }
}

Type guard

static boolean isValidUrl(String s) {
  if (s == null || s.isBlank()) return false;
  try { new java.net.URI(s).toURL(); return true; } catch (Exception e) { return false; }
}

Try / catch

try {
  String absolute = client.url(endpoint);
} catch (IllegalArgumentException e) {
  LOG.error("Configured ALM URL is invalid: {}", e.getMessage());
  throw new ConfigurationException("Fix the devops platform URL in settings", e);
}

Prevention

When it happens

Trigger: Calling url()/toAbsoluteEndPoint where host or endPoint is malformed: missing scheme on host (e.g. 'myserver' instead of 'https://myserver'), illegal characters (spaces, unencoded '#', '?', '|'), an empty or null host with a relative endpoint, or an endPoint that does not start with 'http' while host+endPoint still fails URI parsing.

Common situations: Users enter 'sonarqube.company.com' or 'http://server with space' in the devops platform settings form instead of a fully qualified URL; copy-pasted URLs containing trailing spaces or unencoded special characters; empty host field left after an upgrade.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at server/sonar-alm-client/src/main/java/org/sonar/alm/client/GenericApplicationHttpClient.java:220

    Request.Builder url = new Request.Builder().url(toAbsoluteEndPoint(appUrl, endPoint));
    if (token != null) {
      url.addHeader(devopsPlatformHeaders.getAuthorizationHeader(), token.getAuthorizationHeaderPrefix() + " " + token.getValue());
      devopsPlatformHeaders.getApiVersion().ifPresent(apiVersion ->
        url.addHeader(devopsPlatformHeaders.getApiVersionHeader().orElseThrow(), apiVersion)
      );
    }
    extraHeaders.forEach(url::addHeader);
    return url;
  }

  private static String toAbsoluteEndPoint(String host, String endPoint) {
    if (endPoint.startsWith("http")) {
      return endPoint;
    }
    try {
      return new URI(host + endPoint).toURL().toExternalForm();
    } catch (URISyntaxException | IllegalArgumentException | MalformedURLException e) {
      throw new IllegalArgumentException(String.format("%s is not a valid url", host + endPoint));
    }
  }

  private static String attemptReadContent(okhttp3.Response response) {
    try {
      return readContent(response.body()).orElse(null);
    } catch (IOException e) {
      return null;
    }
  }

  private static Optional<String> readContent(@Nullable ResponseBody body) throws IOException {
    if (body == null) {
      return empty();
    }
    try {
      return of(body.string());
    } finally {

View on GitHub (pinned to 184c821202)