{"record":{"id":"c9b384453975c8bc","repo":"SonarSource/sonarqube","slug":"could-not-parse-gitlab-answer-to-verify-token-scop","errorCode":null,"errorMessage":"Could not parse GitLab answer to verify token scopes. Got a non-json payload as result.","messagePattern":"Could not parse GitLab answer to verify token scopes\\. Got a non-json payload as result\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server/sonar-alm-client/src/main/java/org/sonar/alm/client/gitlab/GitlabApplicationClient.java","lineNumber":163,"sourceCode":"    }\n  }\n\n  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","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-alm-client/src/main/java/org/sonar/alm/client/gitlab/GitlabApplicationClient.java#L145-L181","documentation":"Thrown by GitlabApplicationClient.getPersonalAccessTokenInfo when the GitLab /personal_access_tokens/self endpoint returns 2xx but the body is not valid JSON for a GsonPersonalAccessTokenInfo (JsonSyntaxException). Used to validate the token's scopes.","triggerScenarios":"getPersonalAccessTokenInfo receives an HTTP 200 whose body fails GsonPersonalAccessTokenInfo.parseOne — HTML response, empty body, or unexpected JSON shape (e.g. older GitLab lacking this endpoint variant).","commonSituations":"GitLab version too old to support /personal_access_tokens/self (added in GitLab 16); proxy interstitial; URL pointing at a non-GitLab server.","solutions":["Upgrade GitLab to a version that supports GET /personal_access_tokens/self (GitLab 16+)","Verify manually: curl -H 'PRIVATE-TOKEN: <token>' <gitlabUrl>/api/v4/personal_access_tokens/self","Confirm gitlabUrl points to the GitLab instance and not a proxy returning HTML"],"exampleFix":"// before: GitLab 15.x (endpoint returns unexpected body) \n// after: upgrade GitLab to >=16.0 or use a SonarQube version matching your GitLab","handlingStrategy":"try-catch","validationCode":"curl -sS -H \"PRIVATE-TOKEN: $TOKEN\" \"$GITLAB_URL/api/v4/personal_access_tokens/self\" | jq -e '.scopes'  # requires GitLab 16+","typeGuard":null,"tryCatchPattern":"try { gitlabClient.getPersonalAccessTokenInfo(url, token); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"non-json\")) { checkGitlabVersionSupportsSelfEndpoint(); } }","preventionTips":["Ensure GitLab is version 16+ where /personal_access_tokens/self returns the expected JSON","Keep SonarQube and GitLab versions compatible per the SonarQube docs","Test the endpoint response body is JSON before configuring ALM integration"],"tags":["gitlab","json","token-scopes","parsing"],"backgroundTag":"invalid-json-response","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"}