SonarSource/sonarqube · warning

Cannot mint a GitHub installation token for project '{}': Gi

Error message

Cannot mint a GitHub installation token for project '{}': GitHub App is not installed on repository '{}'

What it means

GithubInstallationTokenProviderImpl.mint logs this warning and returns Optional.empty() when githubApplicationClient.getInstallationId finds no GitHub App installation for the configured app on the bound repository. The project and its GitHub App binding are valid, but at the GitHub side the App is not installed (or not installed on the org/repo containing the bound repository), so no installation ID — and thus no token — can be obtained.

Source

Thrown at server/sonar-webserver-common/src/main/java/org/sonar/server/common/almsettings/github/GithubInstallationTokenProviderImpl.java:134

    try {
      // TOKEN_MINTING_PERMISSIONS, not the plain default: a minted token is pointless if the GitHub
      // App doesn't have 'contents: write' to push the remediation commit it's minted for. Most
      // already-installed apps predate this requirement — there's no in-product way to prompt them
      // to re-approve, so the wrapped message below is the only guidance an admin gets.
      githubAppConfiguration = githubGlobalSettingsValidator.validate(almSetting, GithubAppPermissions.TOKEN_MINTING_PERMISSIONS);
    } catch (IllegalArgumentException e) {
      // Wrapped (with the project key) rather than swallowed to Optional.empty(): unlike the checks
      // above, this isn't a "not bound" case — the binding exists, its GitHub App configuration is
      // just broken (bad credentials, missing permissions, unreachable API, ...). Wrapping instead of
      // rethrowing as-is adds context in one throw (S2139) while still getting the caller a distinct
      // 400 instead of the same 404 as a genuinely unbound project.
      throw new IllegalArgumentException(
        format("Cannot mint a GitHub installation token for project '%s': invalid GitHub App configuration: %s", safeProjectKey, e.getMessage()), e);
    }

    Optional<Long> installationId = githubApplicationClient.getInstallationId(githubAppConfiguration, almRepo);
    if (installationId.isEmpty()) {
      LOG.warn("Cannot mint a GitHub installation token for project '{}': GitHub App is not installed on repository '{}'", safeProjectKey, safeAlmRepo);
      return Optional.empty();
    }

    String repositoryName = bareRepositoryName(almRepo);
    Optional<ExpiringAppInstallationToken> token = githubApplicationClient.createAppInstallationToken(githubAppConfiguration, installationId.get(), repositoryName);
    if (token.isEmpty()) {
      LOG.warn("Failed to mint a GitHub installation token for project '{}' (repository '{}')", safeProjectKey, safeAlmRepo);
      throw new ServerException(HTTP_INTERNAL_ERROR,
        format("Failed to mint a GitHub installation token for project '%s': GitHub App API call failed", safeProjectKey));
    }

    return Optional.of(new GithubInstallationToken(
      token.get().getValue(), token.get().getExpiresAt().format(ISO_OFFSET_DATE_TIME)));
  }

  /**
   * Strips CR/LF from user-controlled values (project key, ALM repo slug) before logging them, so a
   * crafted value cannot forge extra log lines/entries (CWE-117).

View on GitHub (pinned to 184c821202)

Solutions

  1. Install the SonarQube GitHub App on the organization or repository: GitHub > Settings > Integrations > Applications > SonarQube App > Configure > select the repository/org.
  2. If the App is installed with 'select repositories', add the bound repository to the selection.
  3. Verify almRepo matches the actual GitHub repository full name (org/repo) and update the SonarQube binding if it was renamed or transferred.
  4. Check the GitHub App configuration in SonarQube (api/alm_integrations/view_github) points to the right App ID/endpoint.
  5. In automation, treat the empty Optional as 'install the App first' rather than retrying.

Example fix

// before: binding repo 'acme/payments-service', App installed only on 'acme/webapp'
// after (in GitHub): Settings > Applications > SonarQube > Repository access -> add 'payments-service'
// or in SonarQube if repo moved:
POST api/alm_settings/set_github -d project=payments -d almSetting=github-company -d repositoryName=acme-new/payments-service
Defensive patterns

Strategy: fallback

Validate before calling

# Verify App installation via GitHub API before minting
STATUS=$(curl -s -o /dev/null -w '%{http_code}' -H "Authorization: Bearer $GH_APP_JWT" "https://api.github.com/repos/$ORG/$REPO/installation")
[ "$STATUS" = "200" ] || { echo "GitHub App not installed on $ORG/$REPO; install it first" >&2; exit 1; }

Prevention

When it happens

Trigger: Minting for a project bound to repository 'org/repo' where the SonarQube GitHub App has no installation covering that repository: app never installed on the org, installed only on selected repos excluding this one, or almRepo path typos/mismatch (wrong org name, repo renamed).

Common situations: New repo created after the App was installed on a subset of repositories; repo transferred to another org where the App isn't installed; GitHub App uninstalled from the organization; almRepo configured with a different casing/path than actual GitHub repo.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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