SonarSource/sonarqube · error · IllegalArgumentException

Failed to validate configuration, check URL and Private Key

Error message

Failed to validate configuration, check URL and Private Key

What it means

getAppPermissions() performs an authenticated GET /app request to GitHub using a JWT built from the app's private key. If the HTTP call throws an IOException (connection failure, DNS error, TLS problem), this IllegalArgumentException is thrown telling you the URL or Private Key is likely wrong. The original IOException is logged at WARN level with the endpoint.

Source

Thrown at server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClientImpl.java:224

      throw new IllegalArgumentException("Missing permissions; permission granted on " + message);
    }
  }

  @Override
  public List<String> findMissingAppPermissions(GithubAppConfiguration githubAppConfiguration, Map<String, String> permissions) {
    return computeMissingPermissions(permissions, getAppPermissions(githubAppConfiguration));
  }

  private Map<String, String> getAppPermissions(GithubAppConfiguration githubAppConfiguration) {
    AppToken appToken = appSecurity.createAppToken(githubAppConfiguration.getId(), githubAppConfiguration.getPrivateKey());

    String endPoint = "/app";
    GetResponse response;
    try {
      response = githubApplicationHttpClient.get(githubAppConfiguration.getApiEndpoint(), appToken, endPoint);
    } catch (IOException e) {
      LOG.warn(FAILED_TO_REQUEST_BEGIN_MSG + githubAppConfiguration.getApiEndpoint() + endPoint, e);
      throw new IllegalArgumentException("Failed to validate configuration, check URL and Private Key");
    }
    if (response.getCode() == HTTP_OK) {
      return handleResponse(response, endPoint, GsonApp.class)
        .map(GsonApp::getPermissions)
        .orElseThrow(() -> new IllegalArgumentException("Failed to get app permissions, unexpected response body"));
    } else if (response.getCode() == HTTP_UNAUTHORIZED || response.getCode() == HTTP_FORBIDDEN) {
      throw new IllegalArgumentException("Authentication failed, verify the Client Id, Client Secret and Private Key fields");
    } else {
      throw new IllegalArgumentException("Failed to check permissions with Github, check the configuration");
    }
  }

  private static List<String> computeMissingPermissions(Map<String, String> requiredPermissions, Map<String, String> grantedPermissions) {
    return requiredPermissions.entrySet().stream()
      .filter(permission -> !Objects.equals(permission.getValue(), grantedPermissions.get(permission.getKey())))
      .map(Map.Entry::getKey)
      // sorted for a deterministic message: REQUIRED_PERMISSIONS is a Map.of, whose iteration order is randomized per JVM
      .sorted()

View on GitHub (pinned to 184c821202)

Solutions

  1. Check the api endpoint URL is correct and reachable (curl it from the SonarQube host)
  2. Re-paste the GitHub App private key exactly as downloaded from the .pem file, including BEGIN/END lines
  3. Verify the private key belongs to the configured App ID (regenerating a key invalidates old ones)
  4. Check network/proxy/firewall allows outbound HTTPS from the SonarQube server
  5. Inspect the server log for the WARN line with the underlying IOException for the root cause

Example fix

// before (key without headers, breaks JWT signing)
MIIEvQIBADANBgkqh...
// after (full PEM contents of the .pem file)
-----BEGIN RSA PRIVATE KEY-----
MIIEvQIBADANBgkqh...
-----END RSA PRIVATE KEY-----
Defensive patterns

Strategy: try-catch

Validate before calling

try {
  new URL(apiEndpoint).openConnection().connect(); // or an HTTP HEAD check
} catch (IOException e) {
  throw new IllegalStateException("GitHub endpoint unreachable from this host: " + apiEndpoint, e);
}
// also verify the private key parses:
try {
  KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(pemBody)));
} catch (GeneralSecurityException e) {
  throw new IllegalStateException("Private key is malformed", e);
}

Try / catch

try {
  githubApplicationClient.validateConfig(config);
} catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Failed to validate configuration")) {
    // check server WARN log for the underlying IOException; verify URL connectivity and key format
  }
}

Prevention

When it happens

Trigger: Calling getAppPermissions (via validateConfig or findMissingAppPermissions) when githubApplicationHttpClient.get() raises IOException: unreachable host, wrong port, TLS handshake failure, or a malformed private key that prevents creating a valid app JWT.

Common situations: Private Key field contains the raw .pem with wrong formatting/encoding; wrong api endpoint URL or hostname typo; firewall/proxy blocking outbound HTTPS to GitHub; private key not matching the app's registered key (e.g. old rotated key).

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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