spring-projects/spring-ai · error · IllegalArgumentException

Unsupported assistant message class:

Error message

Unsupported assistant message class: 

What it means

createAssistantChatCompletionMessage(Message) only accepts AssistantMessage instances; a Message with MessageType ASSISTANT of another class triggers IllegalArgumentException naming the class. The accepted subtypes (with tool calls) are handled above the throwing branch.

Source

Thrown at models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java:459

	}

	private ChatCompletionMessage createToolChatCompletionMessage(ToolResponseMessage.ToolResponse toolResponse) {
		return new ChatCompletionMessage(toolResponse.responseData(), ChatCompletionMessage.Role.TOOL,
				toolResponse.name(), null, toolResponse.id());
	}

	private ChatCompletionMessage createAssistantChatCompletionMessage(Message message) {
		if (message instanceof AssistantMessage assistantMessage) {
			List<ToolCall> toolCalls = null;

			if (!CollectionUtils.isEmpty(assistantMessage.getToolCalls())) {
				toolCalls = assistantMessage.getToolCalls().stream().map(this::mapToolCall).toList();
			}
			String content = assistantMessage.getText();
			return new ChatCompletionMessage(content, ChatCompletionMessage.Role.ASSISTANT, null, toolCalls, null);
		}
		else {
			throw new IllegalArgumentException("Unsupported assistant message class: " + message.getClass().getName());
		}
	}

	private ChatCompletionMessage createSystemChatCompletionMessage(Message message) {
		String content = message.getText();
		Assert.state(content != null, "content must not be null");
		return new ChatCompletionMessage(content, ChatCompletionMessage.Role.SYSTEM);
	}

	private ChatCompletionMessage createUserChatCompletionMessage(Message message) {
		var content = message.getText();
		Assert.state(content != null, "content must not be null");

		if (message instanceof UserMessage userMessage && !CollectionUtils.isEmpty(userMessage.getMedia())) {
			// @formatter:off
			var contentChunks = Stream.<ChatCompletionMessage.ContentChunk>concat(
				Stream.of(new ChatCompletionMessage.TextChunk(content)),
				this.mapToImageUrlChunks(userMessage)

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Store/replay assistant turns as AssistantMessage instances
  2. Convert custom assistant messages via new AssistantMessage(text, Map.of(), toolCalls)
  3. Check chat memory deserialization returns standard Spring AI message classes

Example fix

// before
history.add(new MyAssistantMsg(text));
// after
history.add(new AssistantMessage(text));
Defensive patterns

Strategy: type-guard

Validate before calling

if (msg.getMessageType() == MessageType.ASSISTANT && !(msg instanceof AssistantMessage)) {
    throw new IllegalArgumentException("assistant messages must be AssistantMessage");
}

Type guard

boolean isAssistantMessage(Message m) {
    return m instanceof AssistantMessage;
}

Try / catch

try {
    model.call(new Prompt(messages));
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Unsupported assistant message class")) {
        logger.error("convert assistant message: {}", e.getMessage());
    } else throw e;
}

Prevention

When it happens

Trigger: A Message with MessageType ASSISTANT that is not an AssistantMessage (e.g., a custom or foreign assistant-message class) reaches the model's message mapping.

Common situations: Custom chat-memory or conversation-history implementations that store assistant turns as their own message class, or mixing message types from another provider integration.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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