SonarSource/sonarqube · error · IllegalArgumentException

Could not parse GitLab answer to verify token. Got a non-jso

Error message

Could not parse GitLab answer to verify token. Got a non-json payload as result.

What it means

Thrown by GitlabApplicationClient.checkToken when the GitLab /user endpoint returns a 2xx response but the body is not valid JSON for a GsonUser (JsonSyntaxException). This validates the personal access token during ALM configuration.

Source

Thrown at server/sonar-alm-client/src/main/java/org/sonar/alm/client/gitlab/GitlabApplicationClient.java:141

  }

  public GsonUser checkToken(String gitlabUrl, String personalAccessToken) {
    String url = format("%s/user", gitlabUrl);

    LOG.debug("get current user : [{}]", url);
    Request.Builder builder = new Request.Builder()
      .addHeader(PRIVATE_TOKEN, personalAccessToken)
      .url(url)
      .get();

    Request request = builder.build();

    String errorMessage = "Could not validate GitLab token. Got an unexpected answer.";
    try (Response response = client.newCall(request).execute()) {
      checkResponseIsSuccessful(response, errorMessage);
      return GsonUser.parse(response.body().string());
    } catch (JsonSyntaxException e) {
      throw new IllegalArgumentException("Could not parse GitLab answer to verify token. Got a non-json payload as result.");
    } catch (IOException e) {
      logException(url, e);
      throw new IllegalArgumentException(errorMessage);
    }
  }

  public GsonPersonalAccessTokenInfo getPersonalAccessTokenInfo(String gitlabUrl, String personalAccessToken) {
    String url = format("%s/personal_access_tokens/self", gitlabUrl);

    LOG.debug("get personal access token info : [{}]", url);
    Request request = new Request.Builder()
      .addHeader(PRIVATE_TOKEN, personalAccessToken)
      .url(url)
      .get()
      .build();

    String errorMessage = "Could not validate GitLab token scopes. Got an unexpected answer.";
    try (Response response = client.newCall(request).execute()) {

View on GitHub (pinned to 184c821202)

Solutions

  1. Verify gitlabUrl is the GitLab instance root and reachable directly
  2. Test manually: curl -H 'PRIVATE-TOKEN: <token>' <gitlabUrl>/user and confirm JSON output
  3. Inspect any proxy in front of GitLab that may inject HTML or modify the response body

Example fix

// before: gitlabUrl = "https://example.com" (not GitLab; returns HTML)
// after: gitlabUrl = "https://gitlab.example.com";
Defensive patterns

Strategy: try-catch

Validate before calling

curl -sS -H "PRIVATE-TOKEN: $TOKEN" "$GITLAB_URL/api/v4/user" | jq -e '.id'  # must return valid user JSON

Try / catch

try { gitlabClient.checkToken(url, token); } catch (IllegalArgumentException e) { if (e.getMessage().contains("non-json")) { checkProxyAndUrl(url); } }

Prevention

When it happens

Trigger: checkToken gets an HTTP 200 whose body is not the expected JSON user object (HTML page, empty body, JSON shape mismatch), failing GsonUser.parse.

Common situations: URL targets something that is not GitLab; a proxy returns HTML; a GitLab version or API gateway returns an unexpected body shape.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


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