SonarSource/sonarqube · error · IllegalStateException

Invalid SAML Login URL

Error message

Invalid SAML Login URL

What it means

SonarqubeRelyingPartyRegistrationRepository.validateLoginUrl() converts the configured SAML login URL string into a java.net.URI and then a URL to validate it. If URI parsing, toURL(), or toExternalForm() throws MalformedURLException, URISyntaxException, or IllegalArgumentException, the configured SSO login URL is not a syntactically valid absolute URL and it throws IllegalStateException.

Source

Thrown at server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SonarqubeRelyingPartyRegistrationRepository.java:76

    RelyingPartyRegistration.Builder builder = RelyingPartyRegistration.withRegistrationId("saml")
      .assertionConsumerServiceLocation(callbackUrl != null ? callbackUrl : ANY_URL)
      .assertionConsumerServiceBinding(Saml2MessageBinding.POST)
      .entityId(samlSettings.getApplicationId())
      .assertingPartyMetadata(metadata -> metadata
        .entityId(samlSettings.getProviderId())
        .singleSignOnServiceLocation(validateLoginUrl(samlSettings.getLoginUrl()))
        .verificationX509Credentials(c -> c.add(Saml2X509Credential.verification(x509Certificate)))
        .wantAuthnRequestsSigned(samlSettings.isSignRequestsEnabled())
      );
    addSignRequestFieldsIfNecessary(builder);
    return builder.build();
  }

  private static String validateLoginUrl(String url) {
    try {
      return new URI(url).toURL().toExternalForm();
    } catch (MalformedURLException | URISyntaxException | IllegalArgumentException e) {
      throw new IllegalStateException("Invalid SAML Login URL", e);
    }
  }

  private void addSignRequestFieldsIfNecessary(RelyingPartyRegistration.Builder builder) {
    //(on SQ) to sign request we need SP private key and certificate
    //(on IDP) to verify request IDP needs SP public key (certificate)

    //(on IDP) to sign response we need IDP private key (embedded)
    //(on SQ) to verify response we need IDP public key (certificate) !mandatory!

    //(on IDP) encryption: we need SP public key (certificate)
    //(on SQ) decryption: we need Service Provide private key and certificate
    Optional<String> serviceProviderPrivateKey = samlSettings.getServiceProviderPrivateKey();

    if (serviceProviderPrivateKey.isEmpty() || samlSettings.getServiceProviderCertificate() == null) {
      if (samlSettings.isSignRequestsEnabled()) {
        throw new IllegalStateException("Sign requests is enabled but SonarQube private key and/or SonarQube certificate is missing");
      }

View on GitHub (pinned to 184c821202)

Solutions

  1. Set sonar.auth.saml.loginUrl to a fully qualified absolute URL, e.g. https://idp.example.com/saml/sso
  2. Escape or remove illegal characters in the URL (spaces, quotes, raw Unicode)
  3. If the IdP gives a relative endpoint, prepend the IdP base URL scheme and host

Example fix

// before
sonar.auth.saml.loginUrl=idp.example.com/saml/sso
// after
sonar.auth.saml.loginUrl=https://idp.example.com/saml/sso
Defensive patterns

Strategy: validation

Validate before calling

static boolean isValidUrl(String url) {
  try {
    return new URI(url).toURL().toExternalForm() != null;
  } catch (MalformedURLException | URISyntaxException | IllegalArgumentException e) {
    return false;
  }
}
// guard: if (!isValidUrl(loginUrl)) fix before calling

Type guard

static boolean isAbsoluteHttpUrl(String s) {
  try { return java.net.URI.create(s).getScheme() != null; } catch (IllegalArgumentException e) { return false; }
}

Try / catch

try {
  repository.builder().build();
} catch (IllegalStateException e) {
  if (e.getMessage().contains("Invalid SAML Login URL")) {
    throw new ConfigurationException("sonar.auth.saml.loginUrl must be absolute, e.g. https://idp/sso");
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling builder()/findByRegistrationId() during SAML initialization with sonar.auth.saml.loginUrl set to something like 'idp.example.com/sso' (no scheme), 'http:/host' (malformed), a URL with illegal characters (unescaped spaces, '<', '>'), or an empty/blank value.

Common situations: Misconfigured sonar.auth.saml.loginUrl copied from IdP documentation without the https:// prefix, values containing unencoded query characters, or settings left blank after enabling SAML.

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/bed604e0753714c3. Report an issue: GitHub.