{"record":{"id":"0010b9693ac21562","repo":"SonarSource/sonarqube","slug":"failed-to-check-permissions-with-github-check-the","errorCode":null,"errorMessage":"Failed to check permissions with Github, check the configuration","messagePattern":"Failed to check permissions with Github, check the configuration","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClientImpl.java","lineNumber":233,"sourceCode":"  private Map<String, String> getAppPermissions(GithubAppConfiguration githubAppConfiguration) {\n    AppToken appToken = appSecurity.createAppToken(githubAppConfiguration.getId(), githubAppConfiguration.getPrivateKey());\n\n    String endPoint = \"/app\";\n    GetResponse response;\n    try {\n      response = githubApplicationHttpClient.get(githubAppConfiguration.getApiEndpoint(), appToken, endPoint);\n    } catch (IOException e) {\n      LOG.warn(FAILED_TO_REQUEST_BEGIN_MSG + githubAppConfiguration.getApiEndpoint() + endPoint, e);\n      throw new IllegalArgumentException(\"Failed to validate configuration, check URL and Private Key\");\n    }\n    if (response.getCode() == HTTP_OK) {\n      return handleResponse(response, endPoint, GsonApp.class)\n        .map(GsonApp::getPermissions)\n        .orElseThrow(() -> new IllegalArgumentException(\"Failed to get app permissions, unexpected response body\"));\n    } else if (response.getCode() == HTTP_UNAUTHORIZED || response.getCode() == HTTP_FORBIDDEN) {\n      throw new IllegalArgumentException(\"Authentication failed, verify the Client Id, Client Secret and Private Key fields\");\n    } else {\n      throw new IllegalArgumentException(\"Failed to check permissions with Github, check the configuration\");\n    }\n  }\n\n  private static List<String> computeMissingPermissions(Map<String, String> requiredPermissions, Map<String, String> grantedPermissions) {\n    return requiredPermissions.entrySet().stream()\n      .filter(permission -> !Objects.equals(permission.getValue(), grantedPermissions.get(permission.getKey())))\n      .map(Map.Entry::getKey)\n      // sorted for a deterministic message: REQUIRED_PERMISSIONS is a Map.of, whose iteration order is randomized per JVM\n      .sorted()\n      .toList();\n  }\n\n  @Override\n  public Optional<Long> getInstallationId(GithubAppConfiguration githubAppConfiguration, String repositorySlug) {\n    AppToken appToken = appSecurity.createAppToken(githubAppConfiguration.getId(), githubAppConfiguration.getPrivateKey());\n    String endpoint = String.format(\"/repos/%s/installation\", repositorySlug);\n    return get(githubAppConfiguration.getApiEndpoint(), appToken, endpoint, GithubBinding.GsonInstallation.class)\n      .map(GithubBinding.GsonInstallation::getId)","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClientImpl.java#L215-L251","documentation":"getAppPermissions in GithubApplicationClientImpl validates a GitHub App's permissions by calling the GitHub API. After handling success and 401/403 cases, any other non-OK HTTP response falls through to this generic IllegalArgumentException, meaning the request failed for a reason not attributable to authentication — typically a misconfigured URL or unexpected server response. It signals the GitHub App binding configuration should be reviewed.","triggerScenarios":"getAppPermissions (via grantedPermissions or findMissingAppPermissions) receives an HTTP response whose code is not 200, 401, or 403 — e.g. 404 from a wrong API URL, 422, or 5xx from GitHub.","commonSituations":"Wrong GitHub API URL configured in the binding (e.g. pointing to GitHub Enterprise with a bad path), GitHub App id/private key mismatch causing a 404 on the app endpoint, transient GitHub 5xx outages, proxy interference altering responses.","solutions":["Verify the GitHub API URL in the SonarQube GitHub binding configuration (github-app.api.url setting) is correct for your deployment (https://api.github.com or the correct GHES endpoint).","Confirm the App ID and private key correspond to an existing GitHub App (a wrong id yields 404).","Enable DEBUG logging for org.sonar.alm.client to capture the endpoint and response code, then retry.","Check GitHub status / network egress (proxy, firewall) for 5xx responses and retry after the outage."],"exampleFix":"// before\nGithubAppConfiguration conf = new GithubAppConfiguration(appId, privateKey, \"https://ghe.example.com/api/\");\n// after\nGithubAppConfiguration conf = new GithubAppConfiguration(appId, privateKey, \"https://ghe.example.com/api/v3\"); // correct GHES API path","handlingStrategy":"try-catch","validationCode":"// before calling\nif (!appUrl.startsWith(\"https://\")) throw new IllegalArgumentException(\"appUrl must be https\");\n// verify app resolvable: GET {appUrl}/apps/{appId} should return 200 with a valid JWT","typeGuard":null,"tryCatchPattern":"try { client.getAppPermissions(conf); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"check the configuration\")) { log.error(\"GitHub binding misconfigured; verify URL/AppId\", e); } throw e; }","preventionTips":["Pin and validate the GitHub API URL for GHES (/api/v3) at startup","Smoke-test the App credentials with a cheap API call after config changes","Monitor GitHub status for 5xx before blaming configuration","Keep App ID and private key in sync with the same GitHub App"],"tags":["github","http","configuration","alm-binding"],"backgroundTag":"http-error-response","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}