{"record":{"id":"a76dd2eb002f4a40","repo":"SonarSource/sonarqube","slug":"missing-permissions-permission-granted-on-s","errorCode":null,"errorMessage":"Missing permissions; permission granted on %s","messagePattern":"Missing permissions; permission granted on (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClientImpl.java","lineNumber":206,"sourceCode":"    // GitHub Enterprise Cloud with data residency - official format: https://api.company.ghe.com\n    return lowerCaseHost.startsWith(\"api.\") && lowerCaseHost.endsWith(\".ghe.com\");\n  }\n\n  @Override\n  public void checkAppPermissions(GithubAppConfiguration githubAppConfiguration) {\n    checkAppPermissions(githubAppConfiguration, GithubAppPermissions.REQUIRED_PERMISSIONS);\n  }\n\n  @Override\n  public void checkAppPermissions(GithubAppConfiguration githubAppConfiguration, Map<String, String> permissions) {\n    Map<String, String> grantedPermissions = getAppPermissions(githubAppConfiguration);\n    List<String> missingPermissions = computeMissingPermissions(permissions, grantedPermissions);\n    if (!missingPermissions.isEmpty()) {\n      String message = missingPermissions.stream()\n        .map(perm -> perm + \" is '\" + grantedPermissions.get(perm) + \"', should be '\" + permissions.get(perm) + \"'\")\n        .collect(Collectors.joining(\", \"));\n\n      throw new IllegalArgumentException(\"Missing permissions; permission granted on \" + message);\n    }\n  }\n\n  @Override\n  public List<String> findMissingAppPermissions(GithubAppConfiguration githubAppConfiguration, Map<String, String> permissions) {\n    return computeMissingPermissions(permissions, getAppPermissions(githubAppConfiguration));\n  }\n\n  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\");","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationClientImpl.java#L188-L224","documentation":"checkAppPermissions() compares the permissions required by the SonarQube GitHub integration against the permissions actually granted to the GitHub App by GitHub. If any required permission is missing or has the wrong access level, it throws with a per-permission breakdown of granted vs expected values. This is a configuration validation error, not a runtime failure.","triggerScenarios":"Calling validateConfig or findMissingAppPermissions when the GitHub App's granted permissions (fetched from GET /app) lack any of the required permissions (e.g. repository_metadata, checks, contents) or grant a lower access level (read instead of read&write).","commonSituations":"GitHub App registered without all permissions SonarQube requires; permissions changed in GitHub App settings but not re-approved by an org admin; access level downgraded from WRITE to READ; app installed on the org before permissions were updated.","solutions":["Open the GitHub App settings > Permissions & events and grant exactly the permissions SonarQube lists as missing, with the required access level","After changing permissions, have an organization owner approve the new permissions so GitHub actually grants them","Reinstall/re-accept the app on the organization if the permission change is pending","Run validateConfig again to confirm the granted permissions match"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"List<String> missing = githubApplicationClient.findMissingAppPermissions(config, requiredPermissions);\nif (!missing.isEmpty()) {\n  throw new IllegalStateException(\"GitHub App is missing permissions: \" + missing\n    + \" — grant them in GitHub App settings and have an org admin approve\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  githubApplicationClient.validateConfig(config);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().startsWith(\"Missing permissions\")) {\n    // surface e.getMessage() to the admin: it lists granted vs required per permission\n  }\n}","preventionTips":["Grant all permissions SonarQube documents (with required access levels) when first registering the App","After changing GitHub App permissions, ensure an org owner approves them","Call findMissingAppPermissions proactively and display the diff to admins instead of failing blind"],"tags":["github","permissions","github-app","configuration"],"backgroundTag":"insufficient-permissions","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"}