{"record":{"id":"80aee737aae48d74","repo":"SonarSource/sonarqube","slug":"could-not-validate-gitlab-token-scopes-got-an-une","errorCode":null,"errorMessage":"Could not validate GitLab token scopes. Got an unexpected answer.","messagePattern":"Could not validate GitLab token scopes\\. Got an unexpected answer\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server/sonar-alm-client/src/main/java/org/sonar/alm/client/gitlab/GitlabApplicationClient.java","lineNumber":166,"sourceCode":"  public GsonPersonalAccessTokenInfo getPersonalAccessTokenInfo(String gitlabUrl, String personalAccessToken) {\n    String url = format(\"%s/personal_access_tokens/self\", gitlabUrl);\n\n    LOG.debug(\"get personal access token info : [{}]\", url);\n    Request request = new Request.Builder()\n      .addHeader(PRIVATE_TOKEN, personalAccessToken)\n      .url(url)\n      .get()\n      .build();\n\n    String errorMessage = \"Could not validate GitLab token scopes. Got an unexpected answer.\";\n    try (Response response = client.newCall(request).execute()) {\n      checkResponseIsSuccessful(response, errorMessage);\n      return GsonPersonalAccessTokenInfo.parseOne(response.body().string());\n    } catch (JsonSyntaxException e) {\n      throw new IllegalArgumentException(\"Could not parse GitLab answer to verify token scopes. Got a non-json payload as result.\");\n    } catch (IOException e) {\n      logException(url, e);\n      throw new IllegalArgumentException(errorMessage);\n    }\n  }\n\n  public void checkWritePermission(String gitlabUrl, String personalAccessToken) {\n    String url = format(\"%s/markdown\", gitlabUrl);\n\n    LOG.debug(\"verify write permission by formating some markdown : [{}]\", url);\n    Request.Builder builder = new Request.Builder()\n      .url(url)\n      .addHeader(PRIVATE_TOKEN, personalAccessToken)\n      .addHeader(\"Content-Type\", MediaTypes.JSON)\n      .post(RequestBody.create(\"{\\\"text\\\":\\\"validating write permission\\\"}\".getBytes(UTF_8)));\n\n    Request request = builder.build();\n\n    String errorMessage = \"Could not validate GitLab write permission. Got an unexpected answer.\";\n    try (Response response = client.newCall(request).execute()) {\n      checkResponseIsSuccessful(response, errorMessage);","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-alm-client/src/main/java/org/sonar/alm/client/gitlab/GitlabApplicationClient.java#L148-L184","documentation":"Thrown by GitlabApplicationClient.getPersonalAccessTokenInfo when the HTTP call to /personal_access_tokens/self fails with IOException (or checkResponseIsSuccessful maps a non-2xx status to this message). The token's scopes could not be validated.","triggerScenarios":"getPersonalAccessTokenInfo: execute()/body().string() throws IOException, or the GitLab API returns a non-successful HTTP status (401 invalid token, 404 endpoint not present in older GitLab, 403 missing scope).","commonSituations":"Token revoked or without 'api' scope; GitLab version without the endpoint (404); network/TLS failure between SonarQube and GitLab.","solutions":["Verify the personal access token is valid and has the 'api' scope","Check the GitLab version supports /personal_access_tokens/self (16+); upgrade or check the logged IOException for details","Ensure network/TLS connectivity from the SonarQube server to GitLab"],"exampleFix":"// before: PAT scopes = [read_user] (insufficient)\n// after: recreate PAT with scopes ['api'] in GitLab user settings","handlingStrategy":"validation","validationCode":"const res = await fetch(`${gitlabUrl}/api/v4/personal_access_tokens/self`, { headers: { 'PRIVATE-TOKEN': token } });\nif (!res.ok) throw new Error(`Token scopes check failed: HTTP ${res.status}`);\nconst info = await res.json();\nif (!info.scopes.includes('api')) throw new Error('Token lacks api scope');","typeGuard":null,"tryCatchPattern":"try { gitlabClient.getPersonalAccessTokenInfo(url, token); } catch (IllegalArgumentException e) { log.error(\"Scopes validation failed: check token validity/scopes and GitLab version\", e); }","preventionTips":["Use a PAT with the 'api' scope and an active expiry date","Confirm GitLab version supports /personal_access_tokens/self to avoid 404","Check connectivity/TLS from the SonarQube server before validating settings"],"tags":["gitlab","token-scopes","http-request","network"],"backgroundTag":"http-request-failed","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}