spring-projects/spring-ai · error · IllegalStateException
Unexpected JSON token %s!
Error message
Unexpected JSON token %s!
What it means
The ContentChunk deserializer expects the message content JSON to be either a String or a START_ARRAY token. If the first token is anything else (object, number, boolean), it throws IllegalStateException('Unexpected JSON token %s!').
Source
Thrown at models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/api/MistralAiApi.java:1575
List<ContentChunk> contentChunks = new ArrayList<>();
while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
jsonToken = jsonParser.currentToken();
if (jsonToken == JsonToken.START_OBJECT) {
var contentChunk = jsonParser.readValueAs(ContentChunk.class);
contentChunks.add(contentChunk);
}
else {
throw new IllegalStateException(
"Unexpected JSON token %s within the array!".formatted(jsonToken));
}
}
return List.copyOf(contentChunks);
}
throw new IllegalStateException("Unexpected JSON token %s!".formatted(jsonToken));
}
}
}
/**
* Represents a chat completion response returned by model, based on the provided
* input.
*
* @param id A unique identifier for the chat completion.
* @param object The object type, which is always chat.completion.
* @param created The Unix timestamp (in seconds) of when the chat completion was
* created.
* @param model The model used for the chat completion.
* @param choices A list of chat completion choices.
* @param usage Usage statistics for the completion request.
*/View on GitHub (pinned to 98a7beda4f)
Solutions
- Inspect the raw response JSON and ensure 'content' is either a string or an array of objects.
- Fix or regenerate mocks/recorded fixtures to the correct schema.
- Upgrade the Spring AI Mistral module if the API response shape changed.
Example fix
// before
{"content": {"text": "hi"}}
// after
{"content": "hi"} Defensive patterns
Strategy: try-catch
Validate before calling
JsonNode c = payload.get("content");
if (c != null && !(c.isTextual() || c.isArray())) {
throw new IllegalStateException("content must be string or array, got: " + c.getNodeType());
} Try / catch
try {
ChatResponse r = chatModel.call(prompt);
} catch (IllegalStateException e) {
if (e.getMessage().matches("Unexpected JSON token .*")) { /* inspect raw response body, fix gateway/fixtures */ }
} Prevention
- Check intermediary proxies/gateways for response-body rewriting.
- Validate recorded responses against the Mistral OpenAPI schema in CI.
- Keep the Spring AI Mistral dependency current with the deployed API version.
When it happens
Trigger: Deserializing a Mistral response where 'content' is a JSON object or other non-string, non-array value, e.g. {"content": {"text": "hi"}}.
Common situations: Proxy/gateway layers rewriting the response body; API version drift between Mistral and the pinned Spring AI client; corrupted or hand-modified recorded responses.
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
- Unexpected JSON token %s within the array!
- Unknown ResponseFormat type:
- Cannot deserialize ThinkOption from token:
- Conversion from JSON to %s failed
- Conversion from JSON to %s failed
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/8a56996b93cb7f72.
Report an issue: GitHub.