spring-projects/spring-ai · error · IllegalArgumentException

Unsupported message type: %s

Error message

Unsupported message type: %s

What it means

Prompt.instructionsCopy() deep-copies the message list but only knows UserMessage, AssistantMessage, SystemMessage and ToolResponseMessage. Any other Message implementation passed into a Prompt triggers this IllegalArgumentException, because PromptTemplate/Prompt cannot safely copy an unknown message type.

Source

Thrown at spring-ai-model/src/main/java/org/springframework/ai/chat/prompt/Prompt.java:216

		List<Message> messagesCopy = new ArrayList<>();
		this.messages.forEach(message -> {
			if (message instanceof UserMessage userMessage) {
				messagesCopy.add(userMessage.copy());
			}
			else if (message instanceof SystemMessage systemMessage) {
				messagesCopy.add(systemMessage.copy());
			}
			else if (message instanceof AssistantMessage assistantMessage) {
				messagesCopy.add(assistantMessage.copy());
			}
			else if (message instanceof ToolResponseMessage toolResponseMessage) {
				messagesCopy.add(ToolResponseMessage.builder()
					.responses(new ArrayList<>(toolResponseMessage.getResponses()))
					.metadata(new HashMap<>(toolResponseMessage.getMetadata()))
					.build());
			}
			else {
				throw new IllegalArgumentException("Unsupported message type: " + message.getClass().getName());
			}
		});

		return messagesCopy;
	}

	/**
	 * Augments the first system message in the prompt with the provided function. If no
	 * system message is found, a new one is created with the provided text.
	 * @return a new {@link Prompt} instance with the augmented system message.
	 */
	public Prompt augmentSystemMessage(Function<SystemMessage, SystemMessage> systemMessageAugmenter) {
		var messagesCopy = new ArrayList<>(this.messages);
		boolean found = false;
		for (int i = 0; i < messagesCopy.size(); i++) {
			Message message = messagesCopy.get(i);
			if (message instanceof SystemMessage systemMessage) {
				messagesCopy.set(i, systemMessageAugmenter.apply(systemMessage));

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Use only supported Message types: SystemMessage, UserMessage, AssistantMessage, ToolResponseMessage.
  2. Implement your custom message by extending AssistantMessage/UserMessage so it matches an accepted branch.
  3. Serialize the custom message's content into a standard UserMessage before constructing the Prompt.

Example fix

// before
Prompt p = new Prompt(List.of(new MyCustomMessage("hi")));
// after
Prompt p = new Prompt(List.of(new UserMessage("hi")));
Defensive patterns

Strategy: validation

Validate before calling

List.of("SystemMessage","UserMessage","AssistantMessage","ToolResponseMessage").contains(msg.getClass().getSimpleName());

Type guard

boolean isSupportedMessage(Message m) { return m instanceof SystemMessage || m instanceof UserMessage || m instanceof AssistantMessage || m instanceof ToolResponseMessage; }

Try / catch

try { Prompt copy = prompt.copy(); } catch (IllegalArgumentException e) { logger.error("unsupported message type in prompt", e); }

Prevention

When it happens

Trigger: Building a Prompt with a custom Message implementation (or a null/unexpected type in the list) and then calling copy() or builder(), which invokes instructionsCopy().

Common situations: Custom Message classes from older Spring AI versions or third-party integrations after an upgrade that added ToolResponseMessage handling; passing MockMessage-style test doubles.

Related errors


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