{"record":{"id":"8a56996b93cb7f72","repo":"spring-projects/spring-ai","slug":"unexpected-json-token-s","errorCode":null,"errorMessage":"Unexpected JSON token %s!","messagePattern":"Unexpected JSON token (.+?)!","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":1575,"sourceCode":"\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 *\n\t * @param id A unique identifier for the chat completion.\n\t * @param object The object type, which is always chat.completion.\n\t * @param created The Unix timestamp (in seconds) of when the chat completion was\n\t * created.\n\t * @param model The model used for the chat completion.\n\t * @param choices A list of chat completion choices.\n\t * @param usage Usage statistics for the completion request.\n\t */","sourceCodeStart":1557,"sourceCodeEnd":1593,"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#L1557-L1593","documentation":"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!').","triggerScenarios":"Deserializing a Mistral response where 'content' is a JSON object or other non-string, non-array value, e.g. {\"content\": {\"text\": \"hi\"}}.","commonSituations":"Proxy/gateway layers rewriting the response body; API version drift between Mistral and the pinned Spring AI client; corrupted or hand-modified recorded responses.","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."],"exampleFix":"// before\n{\"content\": {\"text\": \"hi\"}}\n// after\n{\"content\": \"hi\"}","handlingStrategy":"try-catch","validationCode":"JsonNode c = payload.get(\"content\");\nif (c != null && !(c.isTextual() || c.isArray())) {\n    throw new IllegalStateException(\"content must be string or array, got: \" + c.getNodeType());\n}","typeGuard":null,"tryCatchPattern":"try {\n    ChatResponse r = chatModel.call(prompt);\n} catch (IllegalStateException e) {\n    if (e.getMessage().matches(\"Unexpected JSON token .*\")) { /* inspect raw response body, fix gateway/fixtures */ }\n}","preventionTips":["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."],"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"}