SonarSource/sonarqube · error · IllegalStateException

Error while deserializing GraphQL payload: %s. %s

Error message

Error while deserializing GraphQL payload: %s. %s

What it means

After a successful HTTP call, deserializeValidAnswerOrThrow parses the response body into a typed GsonGraphQlAnswer. Any exception during body reading or Gson deserialization (malformed JSON, HTML error page, unexpected payload shape) is wrapped in an IllegalStateException whose message includes the original exception text and the raw body for diagnosis.

Source

Thrown at server/sonar-server-common/src/main/java/org/sonar/server/common/graphql/GraphQlClient.java:154

      return deserializeValidAnswerOrThrow(answerDataType, response);
    }
  }

  private static <T> GsonGraphQlAnswer<T> deserializeValidAnswerOrThrow(Type answerDataType, Response response) {
    GsonGraphQlAnswer<T> graphQlAnswer;
    Function<String, GsonGraphQlAnswer<T>> toObject = stringPayload -> GSON.fromJson(stringPayload, answerDataType);
    Optional<String> bodyString = Optional.empty();
    try {
      bodyString = Optional.ofNullable(response.body()).map(body -> {
        try {
          return body.string();
        } catch (IOException e) {
          throw new IllegalStateException(e);
        }
      });
      graphQlAnswer = bodyString.map(toObject).orElseThrow();
    } catch (Exception exception) {
      throw new IllegalStateException(format("Error while deserializing GraphQL payload: %s. %s", exception.getMessage(), bodyString), exception);
    }
    if (!graphQlAnswer.isValid()) {
      throw new IllegalStateException("The GraphQl answer contains errors: " + graphQlAnswer.errors());
    }
    return graphQlAnswer;
  }

}

View on GitHub (pinned to 184c821202)

Solutions

  1. Inspect the raw body embedded in the exception message — if it is HTML, the request is being intercepted (login page, error page).
  2. Verify authentication so the request reaches the actual GraphQL endpoint.
  3. Check that the expected answer type still matches the server's GraphQL schema (upgrade client types after server upgrades).
  4. Test the same query manually (curl) to compare the payload.
  5. Check for proxy/CDN interference altering the response.

Example fix

// before
Request request = new Request.Builder().url(baseUrl).build();
// after
Request request = new Request.Builder()
  .url(baseUrl + "/api/graphql")
  .header("Authorization", "Bearer " + token)
  .build();
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the endpoint returns JSON, not an HTML page, before parsing:
// curl -H "Authorization: Bearer $TOKEN" -H "Accept: application/json" $BASE/api/graphql

Try / catch

try {
  return graphQlClient.fetchValidDataOrThrow(type, request);
} catch (IllegalStateException e) {
  if (e.getMessage().contains("<html")) throw new AuthenticationException("Intercepted by login/error page");
  throw e;
}

Prevention

When it happens

Trigger: The GraphQL endpoint returns a 2xx response whose body is not a valid JSON GraphQL answer: proxy or auth pages returning HTML with 200, truncated responses, or a schema/type change making the declared answer type unparseable.

Common situations: Reverse proxies or SSO redirects serving HTML login pages with status 200; API version drift after a server upgrade; gzip/encoding misconfiguration; network middleware corrupting the body.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/672d94ea24373886. Report an issue: GitHub.