SonarSource/sonarqube · error · IllegalArgumentException
Unexpected response from Bitbucket server
Error message
Unexpected response from Bitbucket server
What it means
validateResponseBody runs on successful (2xx) responses before the handler: it parses the body as a generic Gson Object to prove it is valid JSON. If parsing throws JsonParseException, the client throws IllegalArgumentException('Unexpected response from Bitbucket server') — the server replied 200 OK with a non-JSON body.
Source
Thrown at server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucketserver/BitbucketServerRestClient.java:178
}
protected static <G> G applyHandler(Function<String, G> handler, String bodyString) {
try {
return handler.apply(bodyString);
} catch (JsonSyntaxException e) {
LOG.info(UNABLE_TO_CONTACT_BITBUCKET_SERVER + ". Unexpected body response was : [{}]", bodyString);
LOG.info(UNABLE_TO_CONTACT_BITBUCKET_SERVER + ": {}", e.getMessage(), e);
throw new IllegalArgumentException(UNABLE_TO_CONTACT_BITBUCKET_SERVER + ", got an unexpected response", e);
}
}
protected static void validateResponseBody(boolean isSuccessful, String bodyString) {
if (isSuccessful) {
try {
buildGson().fromJson(bodyString, Object.class);
} catch (JsonParseException e) {
LOG.info(UNEXPECTED_RESPONSE_FROM_BITBUCKET_SERVER + " : [{}]", bodyString);
throw new IllegalArgumentException(UNEXPECTED_RESPONSE_FROM_BITBUCKET_SERVER, e);
}
}
}
protected static void handleHttpErrorIfAny(boolean isSuccessful, int httpCode, String bodyString) {
if (!isSuccessful) {
String errorMessage = getErrorMessage(bodyString);
LOG.info(UNABLE_TO_CONTACT_BITBUCKET_SERVER + ": {} {}", httpCode, errorMessage);
if (httpCode == HTTP_UNAUTHORIZED) {
throw new BitbucketServerException(HTTP_UNAUTHORIZED, "Invalid personal access token");
} else if (httpCode == HTTP_NOT_FOUND) {
throw new BitbucketServerException(HTTP_NOT_FOUND, "Error 404. The requested Bitbucket server is unreachable.");
}
throw new IllegalArgumentException(UNABLE_TO_CONTACT_BITBUCKET_SERVER);
}
}
protected static boolean equals(@Nullable MediaType first, @Nullable MediaType second) {View on GitHub (pinned to 184c821202)
Solutions
- Inspect the logged body '[...]' in the server log to identify what the 200 response actually contained.
- Fix the server URL so REST calls hit Bitbucket directly rather than an SSO or proxy page.
- Bypass the SSO/proxy for SonarQube (IP allowlist or service account) so REST endpoints return JSON.
- Check proxy/load-balancer health-page behavior for the configured host.
Defensive patterns
Strategy: try-catch
Try / catch
try {
// call client
} catch (IllegalArgumentException e) {
if ("Unexpected response from Bitbucket server".equals(e.getMessage())) {
// 2xx but non-JSON: check the logged body, likely SSO login page or proxy HTML
}
} Prevention
- Verify REST calls return Content-Type application/json by testing with curl.
- Configure SSO to bypass non-interactive clients or use a service account.
- Ensure load balancers don't serve HTML maintenance pages with 200 status to API clients.
When it happens
Trigger: An HTTP 200 response whose body is not JSON at all — e.g. an HTML SSO login page, a proxy maintenance page, or gzip/charset mangling — detected while calling any Bitbucket REST endpoint via getBodyString.
Common situations: SSO/SSO plugins redirecting REST calls to an HTML login form with 200 status; transparent proxies or load balancers serving error/maintenance HTML; misconfigured URL pointing to a web app root instead of the Bitbucket API host.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- Response from Azure for request [%s] could not be parsed: [%
- url must start with http:// or https://
- Unable to contact Bitbucket server
- Unable to contact Bitbucket server, got an unexpected respon
- Invalid personal access token
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/1507d1abb44a275c.
Report an issue: GitHub.