SonarSource/sonarqube · error · GitlabServerException

Your GitLab token has insufficient scope

Error message

Your GitLab token has insufficient scope

What it means

checkResponseIsSuccessful detects GitLab's 403 'insufficient_scope' error response and throws GitlabServerException 'Your GitLab token has insufficient scope'. The token is valid and not expired, but it lacks the OAuth scopes (notably 'api') required for the operation SonarQube attempted.

Source

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

    } catch (UnsupportedEncodingException ex) {
      throw new IllegalStateException(ex.getCause());
    }
  }

  protected static void checkResponseIsSuccessful(Response response) throws IOException {
    checkResponseIsSuccessful(response, "GitLab Merge Request did not happen, please check your configuration");
  }

  protected static void checkResponseIsSuccessful(Response response, String errorMessage) throws IOException {
    if (!response.isSuccessful()) {
      String body = response.body().string();
      LOG.error("Gitlab API call to [{}] failed with {} http code. gitlab response content : [{}]", response.request().url(), response.code(), body);
      if (isTokenRevoked(response, body)) {
        throw new GitlabServerException(response.code(), "Your GitLab token was revoked");
      } else if (isTokenExpired(response, body)) {
        throw new GitlabServerException(response.code(), "Your GitLab token is expired");
      } else if (isInsufficientScope(response, body)) {
        throw new GitlabServerException(response.code(), "Your GitLab token has insufficient scope");
      } else if (response.code() == HTTP_FORBIDDEN) {
        throw new GitlabServerException(response.code(), "Forbidden access to GitLab. Verify your token's permissions and IP restrictions.");
      } else if (response.code() == HTTP_TOO_MANY_REQUESTS) {
        throw new GitlabServerException(response.code(), "GitLab API rate limit exceeded. Try again later.");
      } else if (response.code() == HTTP_UNAUTHORIZED) {
        throw new GitlabServerException(response.code(), "Invalid personal access token");
      } else if (response.isRedirect()) {
        throw new GitlabServerException(response.code(), "Request was redirected, please provide the correct URL");
      } else {
        throw new GitlabServerException(response.code(), errorMessage);
      }
    }
  }

  private static boolean isTokenRevoked(Response response, String body) {
    if (response.code() == HTTP_UNAUTHORIZED) {
      try {
        Optional<GsonError> gitlabError = GsonError.parseOne(body);

View on GitHub (pinned to 184c821202)

Solutions

  1. Recreate the GitLab PAT with the 'api' scope (plus read_user) selected.
  2. Update the new token in SonarQube's GitLab DevOps integration configuration.
  3. Verify GitLab instance policy does not down-scope tokens (e.g. read_api-only enforcement).
  4. For project-level bindings, ensure the token owner is at least Maintainer on the target project.

Example fix

// before: token scopes = ['read_api']
// after: recreate PAT with scopes
scopes: ["api", "read_user"]
Defensive patterns

Strategy: validation

Validate before calling

// Validate scopes before configuring the integration
JsonObject info = getJson(gitlabUrl + "/api/v4/personal_access_tokens/self", token);
JsonArray scopes = info.getAsJsonArray("scopes");
if (!scopes.toString().contains("api")) {
  throw new IllegalStateException("GitLab PAT lacks the 'api' scope; recreate it with api + read_user");
}

Prevention

When it happens

Trigger: Any GitLab API call via checkResponseIsSuccessful (checkProjectAccess, checkToken, getPersonalAccessTokenInfo, checkWritePermission, createProjectAccessToken) receives 403 with an insufficient_scope body at GitlabApplicationClient.java:216.

Common situations: PAT created with only read_api or read_user but the integration needs api scope; a read-only token used for creating projects or project access tokens; organization policy restricting token scopes.

Understand the failure class

Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.

Related errors


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