spring-projects/spring-ai · error · IllegalStateException

Unexpected JSON token %s within the array!

Error message

Unexpected JSON token %s within the array!

What it means

The ContentChunk deserializer iterates a JSON array expecting each token to be START_OBJECT so it can read a ContentChunk. If it encounters any other JSON token (string, number, array) inside the array, it throws IllegalStateException('Unexpected JSON token %s within the array!').

Source

Thrown at models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/api/MistralAiApi.java:1567

			public Object deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
				var jsonToken = jsonParser.currentToken();

				if (jsonToken == JsonToken.VALUE_STRING) {
					return jsonParser.getValueAsString();
				}

				if (jsonToken == JsonToken.START_ARRAY) {
					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.
	 *

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Verify the JSON payload: content arrays must contain objects like {"type":"text","text":"..."}.
  2. Fix mock/fixture data to match the Mistral schema with object elements.
  3. Upgrade spring-ai-mistral-ai if the upstream API changed its content shape.

Example fix

// before
{"content": ["hello"]}
// after
{"content": [{"type": "text", "text": "hello"}]}
Defensive patterns

Strategy: try-catch

Validate before calling

// validate fixture JSON before replay
JsonNode arr = payload.get("content");
if (arr != null && arr.isArray()) {
    for (JsonNode n : arr) if (!n.isObject()) throw new IllegalStateException("content array has non-object element");
}

Try / catch

try {
    ChatResponse r = chatModel.call(prompt);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("Unexpected JSON token")) { /* log raw payload; fix fixtures or upgrade client */ }
}

Prevention

When it happens

Trigger: Deserializing a Mistral API message whose content array contains raw strings/numbers instead of JSON objects, or feeding hand-crafted JSON like ["a","b"] into the deserializer.

Common situations: Mock server fixtures with wrong content shape; Mistral API contract changes; replaying recorded HTTP traffic from a different API version.

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 spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/aaa8c9abc1c9b47f. Report an issue: GitHub.