{"record":{"id":"2936145751bed1f0","repo":"SonarSource/sonarqube","slug":"response-from-azure-for-request-s-could-not-be","errorCode":null,"errorMessage":"Response from Azure for request [%s] could not be parsed: [%s]","messagePattern":"Response from Azure for request \\[(.+?)\\] could not be parsed: \\[(.+?)\\]","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server/sonar-alm-client/src/main/java/org/sonar/alm/client/azure/AzureDevOpsHttpClient.java","lineNumber":215,"sourceCode":"      checkResponseIsSuccessful(response);\n    } catch (IOException e) {\n      throw new IllegalArgumentException(\n        String.format(UNABLE_TO_CONTACT_AZURE_SERVER_MESSAGE_FORMAT, UNABLE_TO_CONTACT_AZURE_SERVER, request.url(), e.getMessage()),\n        e);\n    }\n  }\n\n  protected <G> G doGet(String token, HttpUrl url, Function<Response, G> handler) {\n    Request request = prepareRequestWithToken(token, GET, url, null);\n    return doCall(request, handler);\n  }\n\n  protected <G> G doCall(Request request, Function<Response, G> handler) {\n    try (Response response = client.newCall(request).execute()) {\n      checkResponseIsSuccessful(response);\n      return handler.apply(response);\n    } catch (JsonSyntaxException e) {\n      throw new IllegalArgumentException(\n        String.format(\"Response from Azure for request [%s] could not be parsed: [%s]\", request.url(), e.getMessage()),\n        e);\n    } catch (IOException e) {\n      throw new IllegalArgumentException(\n        String.format(UNABLE_TO_CONTACT_AZURE_SERVER_MESSAGE_FORMAT, UNABLE_TO_CONTACT_AZURE_SERVER, request.url(), e.getMessage()),\n        e);\n    }\n  }\n\n  protected static Request prepareRequestWithToken(String token, String method, HttpUrl url, @Nullable RequestBody body) {\n    return new Request.Builder()\n      .method(method, body)\n      .url(url)\n      .addHeader(\"Authorization\", encodeToken(\"accessToken:\" + token))\n      .build();\n  }\n\n  protected static void checkResponseIsSuccessful(Response response) throws IOException {","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-alm-client/src/main/java/org/sonar/alm/client/azure/AzureDevOpsHttpClient.java#L197-L233","documentation":"doCall(request, handler) applies the response-parsing handler and catches JsonSyntaxException, rethrowing IllegalArgumentException with 'Response from Azure for request [%s] could not be parsed'. It means Azure answered with HTTP success but the body was not the expected JSON (Gson failed to deserialize it).","triggerScenarios":"handler.apply(response) throws JsonSyntaxException during doGet: response body is HTML (login/proxy page), empty, truncated, or JSON whose shape does not match the expected DTO.","commonSituations":"Reverse proxy or SSO intercepting the API call and returning an HTML login page with 200; Azure DevOps Server version returning a different JSON schema; proxy mangling the body; response truncated by a network device.","solutions":["Log/inspect the raw response body for the failing request URL to see what was actually returned.","Bypass or correctly authenticate the proxy/SSO that returns an HTML page instead of JSON.","Verify the Azure DevOps Server version is supported by your SonarQube version; upgrade one side if schemas differ.","Check for intermediate devices (proxies, WAFs) truncating or rewriting the response."],"exampleFix":"// before: response is HTML from SSO login page\n// after: configure SSO bypass/allowlist for /_apis on the proxy so JSON reaches SonarQube","handlingStrategy":"try-catch","validationCode":"static boolean looksLikeJson(Response resp) throws IOException {\n  String contentType = resp.header(\"Content-Type\", \"\");\n  return contentType.contains(\"application/json\");\n}","typeGuard":"static boolean isJsonContentType(String contentType) {\n  return contentType != null && contentType.toLowerCase().contains(\"json\");\n}","tryCatchPattern":"try {\n  List<Repo> repos = client.getRepositories(pat, org);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"could not be parsed\")) {\n    LOG.error(\"Azure returned a non-JSON body (proxy/SSO page?): {}\", e.getCause().getMessage());\n  }\n}","preventionTips":["Ensure proxies/SSO allowlist the /_apis endpoints instead of returning HTML login pages.","Check Content-Type is application/json before parsing responses.","Pin supported Azure DevOps Server / SonarQube version combinations.","Inspect raw bodies in a staging environment after upgrading either product."],"tags":["java","json","azure-devops","parsing"],"backgroundTag":"json-unmarshal-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"}