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
- Renew the personal access token in GitLab (User Settings > Access Tokens > extend expiry or create a new one).
- Update the new token in SonarQube's GitLab integration settings and re-test the configuration.
- Consider GitLab's non-expiring token option (if instance policy allows) or a service-account token with a long expiry plus rotation reminders.
- 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
- Set calendar reminders before the PAT expiry date.
- Prefer no-expiry or long-expiry tokens where instance policy allows, with scheduled rotation.
- Call /personal_access_tokens/self periodically to surface approaching expiry.
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
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Your GitLab token was revoked
- Invalid personal access token
- Your GitLab token has insufficient scope
- Invalid personal access token
- Authentication failed, verify the Client Id, Client Secret a
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/7b9a87dde137370d.
Report an issue: GitHub.