{"record":{"id":"aaa8c9abc1c9b47f","repo":"spring-projects/spring-ai","slug":"unexpected-json-token-s-within-the-array","errorCode":null,"errorMessage":"Unexpected JSON token %s within the array!","messagePattern":"Unexpected JSON token (.+?) within the array!","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/api/MistralAiApi.java","lineNumber":1567,"sourceCode":"\t\t\tpublic Object deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {\n\t\t\t\tvar jsonToken = jsonParser.currentToken();\n\n\t\t\t\tif (jsonToken == JsonToken.VALUE_STRING) {\n\t\t\t\t\treturn jsonParser.getValueAsString();\n\t\t\t\t}\n\n\t\t\t\tif (jsonToken == JsonToken.START_ARRAY) {\n\t\t\t\t\tList<ContentChunk> contentChunks = new ArrayList<>();\n\n\t\t\t\t\twhile (jsonParser.nextToken() != JsonToken.END_ARRAY) {\n\t\t\t\t\t\tjsonToken = jsonParser.currentToken();\n\n\t\t\t\t\t\tif (jsonToken == JsonToken.START_OBJECT) {\n\t\t\t\t\t\t\tvar contentChunk = jsonParser.readValueAs(ContentChunk.class);\n\t\t\t\t\t\t\tcontentChunks.add(contentChunk);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\t\t\t\"Unexpected JSON token %s within the array!\".formatted(jsonToken));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn List.copyOf(contentChunks);\n\t\t\t\t}\n\n\t\t\t\tthrow new IllegalStateException(\"Unexpected JSON token %s!\".formatted(jsonToken));\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Represents a chat completion response returned by model, based on the provided\n\t * input.\n\t *","sourceCodeStart":1549,"sourceCodeEnd":1585,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/api/MistralAiApi.java#L1549-L1585","documentation":"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!').","triggerScenarios":"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.","commonSituations":"Mock server fixtures with wrong content shape; Mistral API contract changes; replaying recorded HTTP traffic from a different API version.","solutions":["Verify the JSON payload: content arrays must contain objects like {\"type\":\"text\",\"text\":\"...\"}.","Fix mock/fixture data to match the Mistral schema with object elements.","Upgrade spring-ai-mistral-ai if the upstream API changed its content shape."],"exampleFix":"// before\n{\"content\": [\"hello\"]}\n// after\n{\"content\": [{\"type\": \"text\", \"text\": \"hello\"}]}","handlingStrategy":"try-catch","validationCode":"// validate fixture JSON before replay\nJsonNode arr = payload.get(\"content\");\nif (arr != null && arr.isArray()) {\n    for (JsonNode n : arr) if (!n.isObject()) throw new IllegalStateException(\"content array has non-object element\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    ChatResponse r = chatModel.call(prompt);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"Unexpected JSON token\")) { /* log raw payload; fix fixtures or upgrade client */ }\n}","preventionTips":["Keep mock servers/recorded fixtures aligned with the actual Mistral response schema.","Prefer recording real API traffic for tests instead of hand-crafted JSON.","Upgrade the Mistral client module when the upstream API contract changes."],"tags":["deserialization","json","mistral"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}