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
- Check the api endpoint URL is correct and reachable (curl it from the SonarQube host)
- Re-paste the GitHub App private key exactly as downloaded from the .pem file, including BEGIN/END lines
- Verify the private key belongs to the configured App ID (regenerating a key invalidates old ones)
- Check network/proxy/firewall allows outbound HTTPS from the SonarQube server
- 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
- Store the private key as the complete .pem file contents including BEGIN/END markers
- Verify outbound HTTPS connectivity to the endpoint from the SonarQube host before configuring
- Re-copy the key after regenerating it in GitHub App settings
- Check the WARN log entry for the root IOException — it names the real cause
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
- Unable to contact Bitbucket Cloud servers: Configure the OAu
- Unable to contact Bitbucket server
- Missing URL
- Invalid URL, %s
- Only http and https schemes are supported
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/6d13e08b94be3cdb.
Report an issue: GitHub.