Spring Boot auto-configuration for chat memory functionality in Spring AI applications
Common issues and solutions for Spring AI Chat Memory.
Problem: Maven/Gradle cannot find the artifact.
Solution:
mvn clean install -UProblem: ClassNotFoundException for ChatMemory or related classes.
Solution:
<!-- Ensure correct dependency -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-model-chat-memory</artifactId>
<version>1.1.2</version>
</dependency>Problem: Beans not created automatically.
Symptoms:
NoSuchBeanDefinitionException for ChatMemorySolution:
Verify dependency is on classpath
Check Spring Boot version compatibility
Ensure auto-configuration is not disabled:
// Don't exclude ChatMemoryAutoConfiguration
@SpringBootApplication(exclude = {})Check logs for auto-configuration report:
logging.level.org.springframework.boot.autoconfigure=DEBUGProblem: BeanDefinitionOverrideException or unexpected bean used.
Solution:
// Use @Primary to specify default bean
@Configuration
public class ChatMemoryConfig {
@Bean
@Primary
public ChatMemory primaryChatMemory() {
return MessageWindowChatMemory.builder()
.maxMessages(50)
.build();
}
}Problem: Null or empty conversation ID passed to ChatMemory methods.
Solution:
public void addMessage(String conversationId, Message message) {
if (conversationId == null || conversationId.trim().isEmpty()) {
throw new IllegalArgumentException("Conversation ID must not be null or empty");
}
chatMemory.add(conversationId, message);
}Problem: All messages lost when application restarts.
Cause: Using default InMemoryChatMemoryRepository.
Solution: Add persistent repository dependency:
<!-- For JDBC -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-model-chat-memory-repository-jdbc</artifactId>
<version>1.1.2</version>
</dependency>Problem: Older messages disappear before expected.
Cause: Default window size is 20 messages.
Solution:
@Bean
public ChatMemory chatMemory(ChatMemoryRepository repository) {
return MessageWindowChatMemory.builder()
.chatMemoryRepository(repository)
.maxMessages(100) // Increase window size
.build();
}Problem: System messages being evicted.
Cause: Not using MessageWindowChatMemory or custom implementation without special handling.
Solution: Use MessageWindowChatMemory which automatically preserves system messages:
MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
.maxMessages(50)
.build();Problem: Table does not exist error.
Solution:
spring.ai.chat.memory.repository.jdbc.initialize-schema=alwaysFor Production: Use migration tools (Flyway/Liquibase) instead:
spring.ai.chat.memory.repository.jdbc.initialize-schema=neverProblem: SQL syntax errors due to incorrect dialect.
Solution: Explicitly set platform:
spring.ai.chat.memory.repository.jdbc.platform=postgresqlProblem: Cannot connect to MongoDB.
Solution:
mongoshspring.data.mongodb.uri=mongodb://localhost:27017/chatmemoryProblem: Indices not created automatically.
Solution:
spring.ai.chat.memory.repository.mongo.create-indices=trueManual Creation:
db.chat_memory.createIndex({ "conversationId": 1 })Problem: InvalidQueryException: Keyspace does not exist.
Solution: Create keyspace manually or enable auto-creation:
spring.ai.chat.memory.repository.cassandra.initialize-schema=trueManual Creation:
CREATE KEYSPACE IF NOT EXISTS my_keyspace
WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};Problem: Cannot authenticate to Neo4j.
Solution: Check credentials:
spring.neo4j.uri=bolt://localhost:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=your-passwordProblem: 429 Too Many Requests errors.
Solution:
@Retryable(
value = {CosmosException.class},
maxAttempts = 3,
backoff = @Backoff(delay = 1000)
)
public void addMessage(String conversationId, Message message) {
chatMemory.add(conversationId, message);
}Problem: Application consuming too much memory.
Causes:
InMemoryChatMemoryRepository with many conversationsSolutions:
.maxMessages(20) // Smaller window@Scheduled(cron = "0 0 2 * * *")
public void cleanup() {
cleanupOldConversations(Duration.ofDays(7));
}Problem: High latency for ChatMemory operations.
Solutions:
Add Indexes:
CREATE INDEX idx_conversation_id ON chat_memory(conversation_id);Connection Pooling:
spring.datasource.hikari.maximum-pool-size=20Batch Operations:
// Instead of multiple adds
chatMemory.add(conversationId, messagesList);Problem: Application crashes with OOM error.
Solutions:
-Xmx2gProblem: Exception when accessing messages concurrently.
Solution: Repository implementations should be thread-safe. If using custom implementation:
private final ConcurrentHashMap<String, List<Message>> store = new ConcurrentHashMap<>();
public List<Message> findByConversationId(String conversationId) {
// Return defensive copy
return new ArrayList<>(store.getOrDefault(conversationId, Collections.emptyList()));
}Problem: Messages appear in wrong order or get lost.
Solution: Implement conversation-level locking:
private final ConcurrentHashMap<String, ReentrantLock> locks = new ConcurrentHashMap<>();
public void addMessageSafely(String conversationId, Message message) {
ReentrantLock lock = locks.computeIfAbsent(conversationId, k -> new ReentrantLock());
lock.lock();
try {
chatMemory.add(conversationId, message);
} finally {
lock.unlock();
}
}Problem: Cannot serialize/deserialize messages.
Causes:
Solutions:
if (mediaData.length > 10_000_000) {
String url = storeExternally(mediaData);
message = new UserMessage("See media at: " + url);
}Problem: Messages lost when switching repositories.
Solution: Implement migration service:
@Service
public class MigrationService {
@Autowired
@Qualifier("sourceRepository")
private ChatMemoryRepository source;
@Autowired
@Qualifier("targetRepository")
private ChatMemoryRepository target;
public void migrate() {
List<String> ids = source.findConversationIds();
for (String id : ids) {
List<Message> messages = source.findByConversationId(id);
target.saveAll(id, messages);
}
}
}Problem: Schema changes break existing data.
Solution: Use database migration tools:
logging.level.org.springframework.ai.chat.memory=DEBUG
logging.level.org.springframework.ai.model.chat.memory=DEBUG@Component
public class ChatMemoryHealthIndicator implements HealthIndicator {
@Autowired
private ChatMemoryRepository repository;
@Override
public Health health() {
try {
repository.findConversationIds();
return Health.up()
.withDetail("repository", repository.getClass().getSimpleName())
.build();
} catch (Exception e) {
return Health.down(e)
.withDetail("error", e.getMessage())
.build();
}
}
}@Component
public class ConfigurationVerifier implements CommandLineRunner {
@Autowired
private ChatMemory chatMemory;
@Autowired
private ChatMemoryRepository repository;
@Override
public void run(String... args) {
logger.info("ChatMemory implementation: {}", chatMemory.getClass().getName());
logger.info("Repository implementation: {}", repository.getClass().getName());
// Test basic operations
String testId = "test-" + UUID.randomUUID();
chatMemory.add(testId, new UserMessage("test"));
List<Message> messages = chatMemory.get(testId);
chatMemory.clear(testId);
logger.info("Chat memory verification: SUCCESS");
}
}Cause: Auto-configuration not triggered or dependency missing.
Solution: Add dependency and verify classpath.
Cause: Schema not initialized.
Solution: Enable schema initialization or create table manually.
Cause: Null conversation ID passed to method.
Solution: Validate inputs before calling ChatMemory methods.
Cause: Null message in list passed to batch add.
Solution: Filter nulls before adding:
messages = messages.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
chatMemory.add(conversationId, messages);If issues persist:
tessl i tessl/maven-org-springframework-ai--spring-ai-autoconfigure-model-chat-memory@1.1.0