SonarSource/sonarqube · error · IllegalStateException

Failed to create GitHub's user access token

Error message

Failed to create GitHub's user access token

What it means

In createUserAccessToken, when the HTTP status is 200 but the response body contains no access_token parameter, SonarQube logs the response and throws this IllegalStateException wrapping the IOException path — actually the IllegalArgumentException for a body without a token, and IllegalStateException with this message when an IOException occurs during the exchange. The comment in code notes a missing token in a 2xx body means the Client ID or Client Secret are incorrect.

Source

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

        throw new IllegalStateException("Failed to create GitHub's user access token. GitHub returned code " + response.getCode() + ".");
      }

      Optional<String> content = response.getContent();
      Optional<UserAccessToken> accessToken = content.flatMap(c -> Arrays.stream(c.split("&"))
          .filter(t -> t.startsWith("access_token="))
          .map(t -> t.split("=")[1])
          .findAny())
        .map(UserAccessToken::new);

      if (accessToken.isPresent()) {
        return accessToken.get();
      }

      // If token is not in the 200's body, it's because the client ID or client secret are incorrect
      LOG.error("Failed to create GitHub's user access token. GitHub's response: {}", content);
      throw new IllegalArgumentException();
    } catch (IOException e) {
      throw new IllegalStateException("Failed to create GitHub's user access token", e);
    }
  }

  @Override
  public GithubAppCredentials convertAppManifest(String apiEndpoint, String code) {
    String endpoint = "/app-manifests/" + URLEncoder.encode(code, StandardCharsets.UTF_8) + "/conversions";
    try {
      // Unauthenticated call: the GitHub App does not exist yet, so no JWT/app token is available.
      ApplicationHttpClient.Response response = githubApplicationHttpClient.post(apiEndpoint, null, endpoint);

      if (response.getCode() != HTTP_CREATED && response.getCode() != HTTP_OK) {
        if (LOG.isDebugEnabled()) {
          LOG.debug("GitHub manifest conversion failed, response body: {}", response.getContent().orElse(""));
        }
        throw new IllegalStateException(
          "Failed to create the GitHub App from manifest. GitHub returned code " + response.getCode());
      }

View on GitHub (pinned to 184c821202)

Solutions

  1. Verify the OAuth App's Client ID and Client Secret in SonarQube match the GitHub OAuth App exactly (regenerate and re-enter the secret).
  2. Check server logs for 'Failed to create GitHub's user access token. GitHub's response:' to see GitHub's actual response body.
  3. Re-run the GitHub authentication flow to get a fresh, unused code (codes are single-use and short-lived).
  4. If caused by IOException, fix connectivity to appUrl and retry.

Example fix

// before (settings)
clientId=Iv1 WRONGID, clientSecret=<old rotated secret>
// after
clientId=Iv1.<correct id from OAuth App>, clientSecret=<current secret regenerated in GitHub>
Defensive patterns

Strategy: validation

Validate before calling

// verify credentials before the flow
if (clientId == null || clientId.isBlank()) throw new IllegalArgumentException("Client Id required");
if (clientSecret == null || clientSecret.isBlank()) throw new IllegalArgumentException("Client Secret required");

Try / catch

try { client.createUserAccessToken(url, clientId, secret, code); } catch (IllegalArgumentException e) { log.error("access_token absent from 2xx body: check Client Id/Secret"); throw e; } catch (IllegalStateException e) { log.error("Token exchange IO failure", e); throw e; }

Prevention

When it happens

Trigger: Calling createUserAccessToken when (a) the body of a successful response lacks 'access_token=' (wrong clientId/clientSecret), producing IllegalArgumentException, or (b) an IOException occurs reading the response, producing this IllegalStateException.

Common situations: Client ID / Client Secret copied from the wrong OAuth App, secrets rotated in GitHub but not in SonarQube, whitespace or decryption failure in the stored secret, transient network interruption mid-response.

Related errors


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