{"record":{"id":"a64cbb5b8ee89aa9","repo":"spring-projects/spring-ai","slug":"unsupported-tool-message-class","errorCode":null,"errorMessage":"Unsupported tool message class: ","messagePattern":"Unsupported tool message class: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java","lineNumber":439,"sourceCode":"\t\treturn switch (message.getMessageType()) {\n\t\t\tcase USER -> Stream.of(createUserChatCompletionMessage(message));\n\t\t\tcase SYSTEM -> Stream.of(createSystemChatCompletionMessage(message));\n\t\t\tcase ASSISTANT -> Stream.of(createAssistantChatCompletionMessage(message));\n\t\t\tcase TOOL -> createToolChatCompletionMessages(message);\n\t\t\tdefault -> throw new IllegalStateException(\"Unknown message type: \" + message.getMessageType());\n\t\t};\n\t}\n\n\tprivate Stream<ChatCompletionMessage> createToolChatCompletionMessages(Message message) {\n\t\tif (message instanceof ToolResponseMessage toolResponseMessage) {\n\t\t\t// @formatter:off\n\t\t\treturn toolResponseMessage.getResponses()\n\t\t\t\t.stream()\n\t\t\t\t.map(this::createToolChatCompletionMessage);\n\t\t\t// @formatter:on\n\t\t}\n\t\telse {\n\t\t\tthrow new IllegalArgumentException(\"Unsupported tool message class: \" + message.getClass().getName());\n\t\t}\n\t}\n\n\tprivate ChatCompletionMessage createToolChatCompletionMessage(ToolResponseMessage.ToolResponse toolResponse) {\n\t\treturn new ChatCompletionMessage(toolResponse.responseData(), ChatCompletionMessage.Role.TOOL,\n\t\t\t\ttoolResponse.name(), null, toolResponse.id());\n\t}\n\n\tprivate ChatCompletionMessage createAssistantChatCompletionMessage(Message message) {\n\t\tif (message instanceof AssistantMessage assistantMessage) {\n\t\t\tList<ToolCall> toolCalls = null;\n\n\t\t\tif (!CollectionUtils.isEmpty(assistantMessage.getToolCalls())) {\n\t\t\t\ttoolCalls = assistantMessage.getToolCalls().stream().map(this::mapToolCall).toList();\n\t\t\t}\n\t\t\tString content = assistantMessage.getText();\n\t\t\treturn new ChatCompletionMessage(content, ChatCompletionMessage.Role.ASSISTANT, null, toolCalls, null);\n\t\t}","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java#L421-L457","documentation":"createToolChatCompletionMessages(Message) only accepts ToolResponseMessage instances; any other class whose messageType is TOOL is rejected with IllegalArgumentException naming the actual class. It is dispatched from createChatCompletionMessages when MessageType == TOOL.","triggerScenarios":"A Message with MessageType TOOL whose runtime class is not ToolResponseMessage (e.g., a custom ToolMessage implementation) reaches the model.","commonSituations":"Custom tool-result message types from other integrations reused with MistralAiChatModel, or adapters that only set the message type without using Spring AI's ToolResponseMessage.","solutions":["Return tool results as Spring AI ToolResponseMessage with ToolResponse entries","Wrap custom tool messages into ToolResponseMessage before calling the model","Check that the message was not produced by a different model integration's API types"],"exampleFix":"// before\nMessage toolMsg = new MyToolMessage(results);\n// after\nMessage toolMsg = new ToolResponseMessage(results.stream()\n    .map(r -> new ToolResponseMessage.ToolResponse(r.id(), r.name(), r.output()))\n    .toList());","handlingStrategy":"type-guard","validationCode":"if (msg.getMessageType() == MessageType.TOOL && !(msg instanceof ToolResponseMessage)) {\n    throw new IllegalArgumentException(\"tool messages must be ToolResponseMessage\");\n}","typeGuard":"boolean isToolResponse(Message m) {\n    return m instanceof ToolResponseMessage;\n}","tryCatchPattern":"try {\n    model.call(new Prompt(messages));\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Unsupported tool message class\")) {\n        logger.error(\"convert tool message: {}\", e.getMessage());\n    } else throw e;\n}","preventionTips":["Always represent tool results with ToolResponseMessage","Wrap custom tool messages before sending to Mistral","Don't reuse other providers' message classes in prompts"],"tags":["mistral","tool-message","type-mismatch","argument"],"backgroundTag":"incompatible-source-type","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}