Skip to content

GigaChatOAuthClient: log full response body on auth failure instead of swallowing it #98

@a-simeshin

Description

@a-simeshin

Problem

When the GigaChat auth endpoint (ngw.devices.sberbank.ru) returns an error with Content-Type: text/html (e.g., 502/503 gateway error page), GigaChatOAuthClient.requestToken() produces an unhelpful exception:

Could not extract response: no suitable HttpMessageConverter found for response type 
[class chat.giga.springai.api.auth.bearer.GigaChatOAuthClient$GigaChatAccessTokenResponse] 
and content type [text/html]

The actual HTML body (which contains the real error — e.g., "502 Bad Gateway", maintenance message, WAF block) is never logged and is lost. This makes it very difficult to diagnose transient auth failures in production.

Root cause

In GigaChatOAuthClient.requestToken():

return this.restClient
    .post()
    .headers(headers -> buildAuthHeaders(headers, this.authToken))
    .body("scope=" + this.scope)
    .retrieve()
    .onStatus(HttpStatusCode::isError, ((request, response) -> {
        log.warn(
            "Token request returned error status: {}, but attempting to parse response body",
            response.getStatusCode());
        // Allow parsing response body even on error status
    }))
    .body(GigaChatAccessTokenResponse.class);

The onStatus handler:

  1. Logs only the HTTP status code (e.g., 502) — not the response body
  2. Swallows the error to attempt body parsing
  3. Body parsing then fails because text/html has no matching HttpMessageConverter for GigaChatAccessTokenResponse
  4. The original HTML content (which explains WHY the auth failed) is lost

Suggested fix

Read and log the full response body in the onStatus handler before attempting deserialization:

.onStatus(HttpStatusCode::isError, ((request, response) -> {
    String body = new String(response.getBody().readAllBytes(), StandardCharsets.UTF_8);
    String contentType = response.getHeaders().getContentType() != null 
        ? response.getHeaders().getContentType().toString() : "unknown";
    
    log.warn("Token request failed: status={}, contentType={}, body={}", 
        response.getStatusCode(), contentType, body);
    
    // If response is not JSON, throw immediately with informative message
    if (!contentType.contains("json")) {
        throw new GigaChatAuthException(
            "Auth endpoint returned non-JSON response (status=" + response.getStatusCode() 
            + ", contentType=" + contentType + "): " + truncate(body, 500));
    }
}))

This way:

  • The actual error page content is visible in logs (502 Bad Gateway, maintenance HTML, WAF block, etc.)
  • Non-JSON responses fail fast with a clear message instead of the cryptic HttpMessageConverter error
  • JSON error responses still attempt parsing as before

Environment

  • spring-ai-gigachat:1.1.2
  • Spring Boot 3.5.11, Java 21
  • Observed in production with parallel shadow calls to GigaChat API

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions