spring-projects/spring-ai · error · IllegalArgumentException
Unsupported message type:
Error message
Unsupported message type:
What it means
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.
Source
Thrown at models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java:704
ToolResponseMessage toolMessage = (ToolResponseMessage) message;
ChatCompletionToolMessageParam.Builder builder = ChatCompletionToolMessageParam.builder();
builder.content(toolMessage.getText() != null ? toolMessage.getText() : "");
builder.role(JsonValue.from(MessageType.TOOL.getValue()));
if (toolMessage.getResponses().isEmpty()) {
return List.of(ChatCompletionMessageParam.ofTool(builder.build()));
}
return toolMessage.getResponses().stream().map(response -> {
String callId = response.id();
String callResponse = response.responseData();
return ChatCompletionMessageParam
.ofTool(builder.toolCallId(callId).content(callResponse).build());
}).toList();
}
else {
throw new IllegalArgumentException("Unsupported message type: " + message.getMessageType());
}
})
.flatMap(List::stream)
.toList();
ChatCompletionCreateParams.Builder builder = ChatCompletionCreateParams.builder();
chatCompletionMessageParams.forEach(builder::addMessage);
OpenAiChatOptions requestOptions = (OpenAiChatOptions) prompt.getOptions();
Assert.state(requestOptions != null, "ChatOptions must not be null");
// Use deployment name if available (for Microsoft Foundry), otherwise use model
// name
if (requestOptions.getDeploymentName() != null) {
builder.model(requestOptions.getDeploymentName());
}
else if (requestOptions.getModel() != null) {View on GitHub (pinned to 98a7beda4f)
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.
Example fix
// before
Prompt prompt = new Prompt(List.of(legacyFunctionMessage));
chatModel.call(prompt); // throws Unsupported message type: FUNCTION
// after
Message assistant = new AssistantMessage("", Map.of(),
List.of(new AssistantMessage.ToolCall(callId, "function", "getWeather", "{\"city\":\"Paris\"}")));
ToolResponseMessage toolMsg = new ToolResponseMessage(
List.of(new ToolResponseMessage.ToolResponse(callId, "getWeather", "{\"temp\":22}")));
Prompt prompt = new Prompt(List.of(assistant, toolMsg));
chatModel.call(prompt); Defensive patterns
Strategy: validation
Validate before calling
java.util.Set<MessageType> supported = java.util.Set.of(MessageType.SYSTEM, MessageType.USER, MessageType.ASSISTANT, MessageType.TOOL);
if (prompt.getMessages().stream().anyMatch(m -> !supported.contains(m.getMessageType()))) {
throw new IllegalStateException("Prompt contains a message type unsupported by OpenAiChatModel");
} Type guard
boolean isTranslatable(Message m) {
return m != null && (m.getMessageType() == MessageType.SYSTEM
|| m.getMessageType() == MessageType.USER
|| m.getMessageType() == MessageType.ASSISTANT
|| m.getMessageType() == MessageType.TOOL);
} Try / catch
try {
return chatModel.call(prompt);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Unsupported message type:")) {
Prompt sanitized = new Prompt(prompt.getMessages().stream()
.filter(m -> SUPPORTED_TYPES.contains(m.getMessageType())).toList(), prompt.getOptions());
return chatModel.call(sanitized);
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unsupported message type:
- Unsupported message type:
- Unsupported response format type:
- Failed to parse toolChoice JSON:
- Unknown tool_choice type:
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/29bb8cd1894df151.
Report an issue: GitHub.