spring-projects/spring-ai · warning

MongoChatMemoryRepository does not support tool call message

Error message

MongoChatMemoryRepository does not support tool call messages. Some messages were filtered out for conversation: + conversationId

What it means

MongoChatMemoryRepository.saveAll() filters out ToolResponseMessage and tool-calling AssistantMessage objects because tool-call messages are not persisted in MongoDB, logging this warning when any were dropped. The conversation is then rewritten (delete + insert) without the tool-call history.

Source

Thrown at memory-repositories/spring-ai-model-chat-memory-repository-mongodb/src/main/java/org/springframework/ai/chat/memory/repository/mongo/MongoChatMemoryRepository.java:75

		return this.mongoTemplate.query(Conversation.class).distinct("conversationId").as(String.class).all();
	}

	@Override
	public List<Message> findByConversationId(String conversationId) {
		var messages = this.mongoTemplate.query(Conversation.class)
			.matching(Query.query(Criteria.where("conversationId").is(conversationId))
				.with(Sort.by("timestamp").ascending()));
		return messages.stream().map(MongoChatMemoryRepository::mapMessage).filter(Objects::nonNull).toList();
	}

	@Override
	public void saveAll(String conversationId, List<Message> messages) {
		List<Message> persistableMessages = messages.stream()
			.filter(m -> !(m instanceof ToolResponseMessage)
					&& !(m instanceof AssistantMessage am && am.hasToolCalls()))
			.toList();
		if (logger.isWarnEnabled() && persistableMessages.size() < messages.size()) {
			logger.warn(
					"MongoChatMemoryRepository does not support tool call messages. Some messages were filtered out for conversation: "
							+ conversationId);
		}
		deleteByConversationId(conversationId);
		var conversations = persistableMessages.stream()
			.map(message -> new Conversation(conversationId,
					new Conversation.Message(message.getText(), message.getMessageType().name(), message.getMetadata()),
					Instant.now()))
			.toList();
		this.mongoTemplate.insert(conversations, Conversation.class);
	}

	@Override
	public void deleteByConversationId(String conversationId) {
		this.mongoTemplate.remove(Query.query(Criteria.where("conversationId").is(conversationId)), Conversation.class);
	}

	public static @Nullable Message mapMessage(Conversation conversation) {

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Filter tool-call messages yourself before calling the repository so the behavior is explicit and warning-free
  2. If tool history is essential, use a memory store that persists tool messages (in-memory, or a custom repository)
  3. Persist tool-call exchanges to a separate Mongo collection yourself and rehydrate them when building the prompt
  4. Upgrade spring-ai and check release notes — tool-call persistence support has been added progressively across repositories

Example fix

// before
chatMemory.add(conversationId, toolResponseMessage); // dropped, warning logged

// after
if (!(msg instanceof ToolResponseMessage)
        && !(msg instanceof AssistantMessage am && am.hasToolCalls())) {
    chatMemory.add(conversationId, msg);
} else {
    toolCallArchive.insert(conversationId, msg); // custom persistence
}
Defensive patterns

Strategy: validation

Validate before calling

boolean persistable(Message m) {
    return !(m instanceof ToolResponseMessage)
        && !(m instanceof AssistantMessage am && am.hasToolCalls());
}

Type guard

static boolean isToolCallMessage(Message m) {
    return m instanceof ToolResponseMessage
        || (m instanceof AssistantMessage am && am.hasToolCalls());
}

Prevention

When it happens

Trigger: Calling saveAll (directly or via addAndGet) with a message list that contains ToolResponseMessage or AssistantMessage.hasToolCalls() for the given conversationId.

Common situations: Agents using function/tool calling with MongoDB-backed ChatMemory; moving from in-memory memory (tool messages retained) to Mongo and losing tool context; conversations appearing shorter or lacking tool results after reload.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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