spring-projects/spring-ai · error · IllegalStateException
unknown message type %s
Error message
unknown message type %s
What it means
CassandraChatMemoryRepository.getMessage() maps stored message-type rows to Spring AI Message objects. Only SYSTEM, USER and ASSISTANT rows are supported; TOOL rows are intentionally filtered out by the caller, and any other (unknown) type hits the default branch, which throws IllegalStateException. This protects against corrupted or forward-incompatible rows written by a newer schema/version.
Source
Thrown at memory-repositories/spring-ai-model-chat-memory-repository-cassandra/src/main/java/org/springframework/ai/chat/memory/repository/cassandra/CassandraChatMemoryRepository.java:240
stmt = stmt.whereColumn(columnName).isEqualTo(QueryBuilder.bindMarker(columnName));
}
stmt = stmt.limit(QueryBuilder.bindMarker("legacy_limit"));
return this.conf.session.prepare(stmt.build());
}
private @Nullable Message getMessage(UdtValue udt) {
String content = Objects.requireNonNullElse(udt.getString(this.conf.messageUdtContentColumn), "");
Map<String, Object> props = Map.of(CONVERSATION_TS, udt.getInstant(this.conf.messageUdtTimestampColumn));
String type = udt.getString(this.conf.messageUdtTypeColumn);
Assert.state(type != null, "message type shouldn't be null");
return switch (MessageType.valueOf(type)) {
case ASSISTANT -> AssistantMessage.builder().content(content).properties(props).build();
case USER -> UserMessage.builder().text(content).metadata(props).build();
case SYSTEM -> SystemMessage.builder().text(content).metadata(props).build();
// this implementation doesn't support tool calls message persistence, so
// TOOL rows are filtered out by the caller
case TOOL -> null;
default -> throw new IllegalStateException(String.format("unknown message type %s", type));
};
}
}
View on GitHub (pinned to 98a7beda4f)
Solutions
- Inspect the offending row with a CQL SELECT and fix or delete the row with the unexpected MESSAGE_TYPE
- Align the library version that reads the table with the version that wrote it
- Extend the switch to handle the new type if you control the code, or pre-filter unknown types in your query
- Delete corrupted rows and re-save the conversation history
Example fix
// before
Row badRow = rows with type 'FUNCTION';
repository.findByConversationId("conv1"); // throws IllegalStateException
// after
cql> DELETE FROM ai_chat_memory WHERE conversation_id = 'conv1' AND message_type = 'FUNCTION'; Defensive patterns
Strategy: validation
Validate before calling
List<Message> msgs = repo.findByConversationId(id);
if (msgs == null || msgs.stream().anyMatch(m -> m.getMessageType() == null)) { /* handle bad data */ } Type guard
boolean isKnownType(String t) { return t != null && List.of("USER","ASSISTANT","SYSTEM","TOOL").contains(t); } Try / catch
try { messages = repo.findByConversationId(id); }
catch (IllegalStateException e) { messages = List.of(); logger.warn("Skipping conversation with unknown message type", e); } Prevention
- Never hand-insert rows into the chat memory table
- Keep reader and writer library versions in sync
- Pre-filter by message type in your own queries
When it happens
Trigger: Reading a conversation whose stored MESSAGE_TYPE column contains a value outside SYSTEM/USER/ASSISTANT/TOOL — e.g. a row written by a different or newer library version, or a manually inserted row with a typo'd type.
Common situations: Schema drift between library versions, manual CQL inserts into the messages table, or rows written by another tool sharing the same table/keyspace.
Related errors
- Unsupported message type:
- %s messages are not supported
- Failed to delete documents by filter
- CassandraChatMemoryRepository does not support tool call mes
- Unknown message type: + type
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/8d379edbe4704875.
Report an issue: GitHub.