SonarSource/sonarqube · error · IllegalArgumentException

Could not parse GitLab answer to verify read permission. Got

Error message

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

What it means

Thrown by GitlabApplicationClient.checkProjectAccess when the GitLab API returns a 2xx response but the body cannot be parsed as the expected JSON project array (JsonSyntaxException). SonarQube uses the parsed projects to verify the token's read permission on a project.

Source

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

  private void checkProjectAccess(@Nullable String gitlabUrl, @Nullable String personalAccessToken, String errorMessage) {
    String url = format("%s/projects", gitlabUrl);

    LOG.debug("get projects : [{}]", url);
    Request.Builder builder = new Request.Builder()
      .url(url)
      .get();

    if (personalAccessToken != null) {
      builder.addHeader(PRIVATE_TOKEN, personalAccessToken);
    }

    Request request = builder.build();

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

  private static void logException(String url, IOException e) {
    String errorMessage = format("Gitlab API call to [%s] failed with error message : [%s]", url, e.getMessage());
    LOG.info(errorMessage, e);
  }

  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)

View on GitHub (pinned to 184c821202)

Solutions

  1. Verify the configured GitLab URL points at the actual GitLab instance root (no trailing path or proxy page)
  2. Test the endpoint manually: curl -H 'PRIVATE-TOKEN: <token>' <gitlabUrl>/projects?membership=true
  3. Check for a proxy/load balancer rewriting responses to HTML error or login pages

Example fix

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

Strategy: try-catch

Validate before calling

curl -sS -o /dev/null -w '%{content_type}' -H "PRIVATE-TOKEN: $TOKEN" "$GITLAB_URL/api/v4/projects?membership=true"  # must be application/json

Try / catch

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

Prevention

When it happens

Trigger: checkReadPermission or checkUrl -> checkProjectAccess gets an HTTP 200 whose body is not valid JSON (HTML error page, empty body, proxy interstitial), causing Gson JsonSyntaxException in Project.parseJsonArray.

Common situations: gitlabUrl points to a non-GitLab server or a reverse proxy returning HTML; wrong path behind a proxy; GitLab returns an unexpected empty 200 body.

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/cae3956664df39a1. Report an issue: GitHub.