{"record":{"id":"29bb8cd1894df151","repo":"spring-projects/spring-ai","slug":"unsupported-message-type-29bb8c","errorCode":null,"errorMessage":"Unsupported message type: ","messagePattern":"Unsupported message type: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java","lineNumber":704,"sourceCode":"\t\t\t\t\tToolResponseMessage toolMessage = (ToolResponseMessage) message;\n\n\t\t\t\t\tChatCompletionToolMessageParam.Builder builder = ChatCompletionToolMessageParam.builder();\n\t\t\t\t\tbuilder.content(toolMessage.getText() != null ? toolMessage.getText() : \"\");\n\t\t\t\t\tbuilder.role(JsonValue.from(MessageType.TOOL.getValue()));\n\n\t\t\t\t\tif (toolMessage.getResponses().isEmpty()) {\n\t\t\t\t\t\treturn List.of(ChatCompletionMessageParam.ofTool(builder.build()));\n\t\t\t\t\t}\n\t\t\t\t\treturn toolMessage.getResponses().stream().map(response -> {\n\t\t\t\t\t\tString callId = response.id();\n\t\t\t\t\t\tString callResponse = response.responseData();\n\n\t\t\t\t\t\treturn ChatCompletionMessageParam\n\t\t\t\t\t\t\t.ofTool(builder.toolCallId(callId).content(callResponse).build());\n\t\t\t\t\t}).toList();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new IllegalArgumentException(\"Unsupported message type: \" + message.getMessageType());\n\t\t\t\t}\n\t\t\t})\n\t\t\t.flatMap(List::stream)\n\t\t\t.toList();\n\n\t\tChatCompletionCreateParams.Builder builder = ChatCompletionCreateParams.builder();\n\n\t\tchatCompletionMessageParams.forEach(builder::addMessage);\n\n\t\tOpenAiChatOptions requestOptions = (OpenAiChatOptions) prompt.getOptions();\n\t\tAssert.state(requestOptions != null, \"ChatOptions must not be null\");\n\n\t\t// Use deployment name if available (for Microsoft Foundry), otherwise use model\n\t\t// name\n\t\tif (requestOptions.getDeploymentName() != null) {\n\t\t\tbuilder.model(requestOptions.getDeploymentName());\n\t\t}\n\t\telse if (requestOptions.getModel() != null) {","sourceCodeStart":686,"sourceCodeEnd":722,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java#L686-L722","documentation":"OpenAiChatModel.createRequest converts Spring AI Message objects (SystemMessage, UserMessage, AssistantMessage, ToolResponseMessage) into OpenAI wire-format ChatCompletionMessageParam objects. If a message in the Prompt has a MessageType outside those four (e.g. MessageType values like FUNCTION from older code or a custom type), the switch-like if/else chain has no branch for it and this IllegalArgumentException is thrown. It is a fail-fast guard: the OpenAI API has no representation for that message type, so sending it would produce an invalid request.","triggerScenarios":"Calling chat()/call()/stream() with a Prompt whose messages list contains a Message whose getMessageType() is neither SYSTEM, USER, ASSISTANT, nor TOOL — e.g. a custom Message implementation returning an unusual MessageType, a legacy FUNCTION-typed message, or a message type introduced by a newer/other Spring AI module.","commonSituations":"Migrating code from the deprecated Spring AI function-calling message types; using a custom ChatMemory that serialized messages and restores them with an unexpected MessageType; mixing message classes from incompatible Spring AI versions; hand-rolling a Message implementation that returns the wrong MessageType enum value.","solutions":["Inspect the Prompt's messages and replace/remove the message whose getMessageType() is not SYSTEM, USER, ASSISTANT, or TOOL before calling the model.","If a legacy FUNCTION message is present, convert it to an AssistantMessage with tool calls plus a ToolResponseMessage pair (the modern OpenAI tool-calling representation).","Check for version mismatches between spring-ai-openai and other Spring AI modules that may introduce message types this OpenAiChatModel build does not handle; align all Spring AI artifacts to the same version.","As a last resort, wrap messages yourself and skip/convert unsupported ones before constructing the Prompt."],"exampleFix":"// before\nPrompt prompt = new Prompt(List.of(legacyFunctionMessage));\nchatModel.call(prompt); // throws Unsupported message type: FUNCTION\n\n// after\nMessage assistant = new AssistantMessage(\"\", Map.of(),\n    List.of(new AssistantMessage.ToolCall(callId, \"function\", \"getWeather\", \"{\\\"city\\\":\\\"Paris\\\"}\")));\nToolResponseMessage toolMsg = new ToolResponseMessage(\n    List.of(new ToolResponseMessage.ToolResponse(callId, \"getWeather\", \"{\\\"temp\\\":22}\")));\nPrompt prompt = new Prompt(List.of(assistant, toolMsg));\nchatModel.call(prompt);","handlingStrategy":"validation","validationCode":"java.util.Set<MessageType> supported = java.util.Set.of(MessageType.SYSTEM, MessageType.USER, MessageType.ASSISTANT, MessageType.TOOL);\nif (prompt.getMessages().stream().anyMatch(m -> !supported.contains(m.getMessageType()))) {\n    throw new IllegalStateException(\"Prompt contains a message type unsupported by OpenAiChatModel\");\n}","typeGuard":"boolean isTranslatable(Message m) {\n    return m != null && (m.getMessageType() == MessageType.SYSTEM\n        || m.getMessageType() == MessageType.USER\n        || m.getMessageType() == MessageType.ASSISTANT\n        || m.getMessageType() == MessageType.TOOL);\n}","tryCatchPattern":"try {\n    return chatModel.call(prompt);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Unsupported message type:\")) {\n        Prompt sanitized = new Prompt(prompt.getMessages().stream()\n            .filter(m -> SUPPORTED_TYPES.contains(m.getMessageType())).toList(), prompt.getOptions());\n        return chatModel.call(sanitized);\n    }\n    throw e;\n}","preventionTips":["Only build Prompts from Spring AI's standard message classes (SystemMessage, UserMessage, AssistantMessage, ToolResponseMessage).","Before persisting/restoring chat memory, verify deserialized messages retain a supported MessageType.","Keep all Spring AI module versions aligned to avoid unhandled message types.","Convert legacy FUNCTION-typed messages to assistant tool calls + tool responses during migration."],"tags":["openai","spring-ai","chat","message-type","illegal-argument"],"backgroundTag":"unsupported-enum-value","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"}