SonarSource/sonarqube · critical · GitlabServerException

Your GitLab token is expired

Error message

Your GitLab token is expired

What it means

checkResponseIsSuccessful maps a failing GitLab response whose body indicates an expired token to GitlabServerException 'Your GitLab token is expired'. GitLab personal access tokens can carry an expiry date; once passed, all API calls fail with 401 and this error is surfaced so the operator knows the token must be renewed, not that permissions are wrong.

Source

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

    try {
      return URLEncoder.encode(value, UTF_8.toString());
    } 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) {

View on GitHub (pinned to 184c821202)

Solutions

  1. Renew the personal access token in GitLab (User Settings > Access Tokens > extend expiry or create a new one).
  2. Update the new token in SonarQube's GitLab integration settings and re-test the configuration.
  3. Consider GitLab's non-expiring token option (if instance policy allows) or a service-account token with a long expiry plus rotation reminders.
  4. Use GitLab project access tokens with automated rotation if the instance supports it.

Example fix

// GitLab: PAT expiring
expires_at: 2024-01-01
// after: extend or recreate
expires_at: 2027-01-01  (or 'no expiration' where policy permits)
Defensive patterns

Strategy: validation

Validate before calling

// Check token expiry before use
JsonObject info = getJson(gitlabUrl + "/api/v4/personal_access_tokens/self", token);
String expiresAt = info.get("expires_at").isJsonNull() ? null : info.get("expires_at").getAsString();
if (expiresAt != null && LocalDate.parse(expiresAt).isBefore(LocalDate.now().plusDays(7))) {
  log.warn("GitLab PAT expires on {} — renew it soon", expiresAt);
}

Prevention

When it happens

Trigger: Any GitLab API call via checkResponseIsSuccessful (checkProjectAccess, checkToken, getPersonalAccessTokenInfo, checkWritePermission, createProjectAccessToken) returns 401 with a body matching the expired-token signature at GitlabApplicationClient.java:214.

Common situations: PAT reached its expiration date configured in GitLab; GitLab instance enforces token expiry policies; a long-lived SonarQube binding outlived the token's validity window.

Understand the failure class

Related errors


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