spring-projects/spring-ai · warning
Unknown message type: + type + , returning generic UserMessa
Error message
Unknown message type: + type + , returning generic UserMessage
What it means
In the message deserialization helper of RedisChatMemoryRepository, when a stored message's 'type' does not match any known kind, this warning is logged and the code degrades gracefully by returning a generic UserMessage built from the stored content and metadata. Unlike the get() path, the message is not dropped — but its original role (assistant/tool/system) is lost.
Source
Thrown at memory-repositories/spring-ai-model-chat-memory-repository-redis/src/main/java/org/springframework/ai/chat/memory/repository/redis/RedisChatMemoryRepository.java:920
JsonArray responseArray = json.getAsJsonArray("toolResponses");
for (JsonElement responseElement : responseArray) {
JsonObject responseJson = responseElement.getAsJsonObject();
String id = responseJson.has("id") ? responseJson.get("id").getAsString() : "";
String name = responseJson.has("name") ? responseJson.get("name").getAsString() : "";
String responseData = responseJson.has("responseData")
? responseJson.get("responseData").getAsString() : "";
toolResponses.add(new ToolResponseMessage.ToolResponse(id, name, responseData));
}
}
return ToolResponseMessage.builder().responses(toolResponses).metadata(metadata).build();
}
// For unknown message types, return a generic UserMessage
if (logger.isWarnEnabled()) {
logger.warn("Unknown message type: " + type + ", returning generic UserMessage");
}
return UserMessage.builder().text(content).metadata(metadata).build();
}
private List<Media> parseMedia(JsonObject json) {
List<Media> mediaList = new ArrayList<>();
if (json.has("media") && json.get("media").isJsonArray()) {
JsonArray mediaArray = json.getAsJsonArray("media");
for (JsonElement mediaElement : mediaArray) {
JsonObject mediaJson = mediaElement.getAsJsonObject();
String mimeTypeString = mediaJson.has("mimeType") ? mediaJson.get("mimeType").getAsString() : null;
if (mimeTypeString != null) {
MimeType mimeType = MimeType.valueOf(mimeTypeString);
Media.Builder mediaBuilder = Media.builder().mimeType(mimeType);
if (mediaJson.has("id")) {
mediaBuilder.id(mediaJson.get("id").getAsString());View on GitHub (pinned to 98a7beda4f)
Solutions
- Check the stored entry's 'type' value in Redis and correct it to a supported kind (user/assistant/system/tool)
- Keep the application's Spring AI version consistent with the version that wrote the data
- Migrate unknown-typed messages to the closest supported type before reading
- Validate JSON written by any custom code sharing the keyspace
- Accept the fallback only if losing the original role is harmless for your use case
Example fix
// before
// stored: {"type":"ToolResponseMessage", ...} -> returned as generic UserMessage
// after
// stored: {"type":"tool", ...} -> correctly rebuilt as ToolResponseMessage Defensive patterns
Strategy: validation
Validate before calling
String type = json.get("type").getAsString();
if (!Set.of("user","assistant","system","tool").contains(type)) {
throw new IllegalStateException("Unreadable stored message type: " + type);
} Type guard
static boolean isSupportedMessageType(String type) {
return type != null && switch (type.toLowerCase()) { case "user","assistant","system","tool" -> true; default -> false; };
} Try / catch
Message m = repositoryMessage(obj);
if (m instanceof UserMessage um && expectedAssistant) { log.warn("message degraded to UserMessage; check stored type"); } Prevention
- Ensure the writing side persists canonical lowercase type tags
- Migrate legacy entries after Spring AI upgrades before reading them
- Add a startup sanity check that samples stored messages and verifies their types
- Treat this warning as data-quality signal, not just noise
When it happens
Trigger: Stored Redis message JSON with a 'type' value the repository doesn't recognize, hit while rebuilding a single message (e.g. from last()/findByConversationId paths).
Common situations: Cross-version Spring AI data in Redis; externally written or hand-edited entries; custom message types persisted without a matching reader; corrupted type strings (case differences, whitespace).
Related errors
- Unknown message type: + type
- Error reserving atomic timestamps for conversation + convers
- Failed to decode Base64 data, storing as string
- Could not parse text search score: ${doc.getString("$score")
- unknown message type %s
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/42147313b5acfc69.
Report an issue: GitHub.