spring-projects/spring-ai · error · IllegalArgumentException

%s messages are not supported

Error message

%s messages are not supported

What it means

Neo4jChatMemoryRepository.findByConversationId() builds Message objects from query records. TOOL records are built via buildToolMessage but are not supported as returned messages in this path; when the resulting message is null the repository throws IllegalArgumentException naming the unsupported type. Essentially TOOL-typed rows cannot be materialized here.

Source

Thrown at memory-repositories/spring-ai-model-chat-memory-repository-neo4j/src/main/java/org/springframework/ai/chat/memory/repository/neo4j/Neo4jChatMemoryRepository.java:116

					message = buildUserMessage(record, messageMap, mediaList);
				}
				else if (msgType.equals(MessageType.ASSISTANT.getValue())) {
					message = buildAssistantMessage(record, messageMap, mediaList);
				}
				else if (msgType.equals(MessageType.SYSTEM.getValue())) {
					SystemMessage.Builder systemMessageBuilder = SystemMessage.builder()
						.text(MessageAttributes.TEXT_CONTENT.stringFrom(messageMap));
					if (!record.get("metadata").isNull()) {
						Map<String, Object> retrievedMetadata = record.get("metadata").asMap();
						systemMessageBuilder.metadata(retrievedMetadata);
					}
					message = systemMessageBuilder.build();
				}
				else if (msgType.equals(MessageType.TOOL.getValue())) {
					message = buildToolMessage(record);
				}
				if (message == null) {
					throw new IllegalArgumentException("%s messages are not supported"
						.formatted(record.get(MessageAttributes.MESSAGE_TYPE.getValue()).asString()));
				}
				message.getMetadata().put("messageType", message.getMessageType());
				return message;
			}, Collectors.toList()));

	}

	@Override
	public void saveAll(String conversationId, List<Message> messages) {
		// First delete existing messages for this conversation
		deleteByConversationId(conversationId);

		// Then add the new messages
		try (Session s = this.config.getDriver().session()) {
			s.executeWriteWithoutResult(tx -> {
				for (Message m : messages) {
					addMessageToTransaction(tx, conversationId, m);

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Remove or re-type the TOOL message nodes for that conversation
  2. Keep TOOL interactions out of the persisted history (filter before saving)
  3. Upgrade/align library versions if TOOL support changed between releases

Example fix

// before
MATCH (m:Message {conversationId:'c1', messageType:'TOOL'}) // read throws IAE
// after
MATCH (m:Message {conversationId:'c1'}) WHERE m.messageType <> 'TOOL' RETURN m
Defensive patterns

Strategy: validation

Validate before calling

// before reading, ensure no TOOL-typed nodes exist for the conversation
// MATCH (m:Message {conversationId:$id, messageType:'TOOL'}) RETURN count(m) == 0

Try / catch

try { messages = repo.findByConversationId(id); }
catch (IllegalArgumentException e) { messages = List.of(); logger.warn("Conversation contains unsupported message nodes", e); }

Prevention

When it happens

Trigger: A conversation in Neo4j contains a node whose messageType is TOOL (or otherwise yields a null message), and findByConversationId is called on that conversation.

Common situations: Tool-call results were persisted by custom code or an older/other tool into the message nodes; mixed-version data; manual graph inserts.

Related errors


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