Skip to content

fix(ai): remove manual Accept-Encoding header so Mistral gzip responses decode#1198

Open
martinconstam wants to merge 1 commit into
conductor-oss:mainfrom
martinconstam:fix/mistral-accept-encoding-gzip
Open

fix(ai): remove manual Accept-Encoding header so Mistral gzip responses decode#1198
martinconstam wants to merge 1 commit into
conductor-oss:mainfrom
martinconstam:fix/mistral-accept-encoding-gzip

Conversation

@martinconstam

Copy link
Copy Markdown
Contributor

Problem

Any LLM task (LLM_TEXT_COMPLETE, LLM_CHAT_COMPLETE, …) using the Mistral provider always fails with:

Error while extracting response for type [org.springframework.ai.mistralai.api.MistralAiApi$ChatCompletion]
and content type [application/json] — caused by: Illegal character ((CTRL-CHAR, code 31)):
only regular white space (\r, \n, \t) is allowed between tokens

code 31 is 0x1F — the first byte of the gzip magic number (0x1F 0x8B). Jackson is being handed a gzip-compressed body that was never decompressed.

Root cause

MistralAI#createMistralAiApi builds the RestClient on an OkHttp3ClientHttpRequestFactory and additionally sets the Accept-Encoding header by hand:

RestClient.builder()
    .requestFactory(factory)
    .defaultHeader("Accept-Encoding", "gzip, deflate")

OkHttp only decompresses a gzip response transparently when it adds the Accept-Encoding header itself (via its BridgeInterceptor). Setting the header explicitly turns that automatic decompression off, so the gzipped body is passed straight to Jackson and parsing fails on the 0x1F byte.

The header was originally added to work around spring-ai#372, but it is unnecessary — and now actively harmful — since the client uses the OkHttp request factory, which handles content encoding on its own.

Fix

Remove the manual Accept-Encoding header and let OkHttp manage compression. Mistral responses then decode correctly.

Tests

Adds MistralAIGzipResponseTest, a regression test using MockWebServer that serves a gzip-encoded chat completion and asserts it is decoded correctly. It fails against the old code (gzip body reaches Jackson undecoded → code 31) and passes with this change. The test needs no API key, so it runs in CI — unlike the existing MistralAITest.IntegrationTests, which are gated on MISTRAL_API_KEY and therefore skipped in CI (which is why this regression went unnoticed).

Impact / scope

  • Present since the initial AI module commit ("Support Agentic flows", Support Agentic flows #745); affects every release that ships the AI module (3.30.0 onward, including 3.31.0-rc.x).
  • Mistral-provider specific; other providers are unaffected by this line.
  • Verified against the live Mistral API and via the new test: responses parse once OkHttp manages the encoding.

@martinconstam martinconstam marked this pull request as draft June 22, 2026 15:18
@martinconstam martinconstam marked this pull request as ready for review June 22, 2026 15:52
…code

The Mistral provider set `Accept-Encoding: gzip, deflate` manually on the
RestClient. OkHttp only decompresses a gzip response transparently when it
adds the Accept-Encoding header itself; setting it explicitly disables that,
so the gzipped body reached Jackson undecoded and parsing failed with
"Illegal character ((CTRL-CHAR, code 31))". Let OkHttp manage compression.

Adds MistralAIGzipResponseTest, a MockWebServer-based regression test that
serves a gzip-encoded chat completion and needs no API key, so it runs in CI
(unlike the existing MISTRAL_API_KEY-gated integration tests).
@martinconstam martinconstam force-pushed the fix/mistral-accept-encoding-gzip branch from a25c5c4 to 9d94b55 Compare June 22, 2026 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants