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

  1. Inspect the Prompt's messages and replace/remove the message whose getMessageType() is not SYSTEM, USER, ASSISTANT, or TOOL before calling the model.
  2. 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).
  3. 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.
  4. 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

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


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/29bb8cd1894df151. Report an issue: GitHub.