OtterMind/Chat2DB · error · BusinessException
ai.chat.history.persistMessagesFailed
ai.chat.history.persistMessagesFailed
Error message
ai.chat.history.persistMessagesFailed
What it means
Thrown by AiChatHistoryServiceImpl.persistMessages in the catch(IOException) while writing <sessionId>.json (parent dir creation or serialization). Args are {path, e.getMessage()}. Any write failure aborts persistence of that session's messages, so an in-flight conversation may not be saved.
Source
Thrown at chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/ai/AiChatHistoryServiceImpl.java:240
return new ArrayList<>();
}
try {
MessagesFile file = objectMapper.readValue(path.toFile(), MessagesFile.class);
return file.getMessages() != null ? file.getMessages() : new ArrayList<>();
} catch (Exception e) {
throw new BusinessException("ai.chat.history.loadMessagesFailed", new Object[]{path, e.getMessage()}, e);
}
}
private void persistMessages(String sessionId, List<AiChatMessage> messages) {
Path path = messagesPath(sessionId);
try {
Files.createDirectories(path.getParent());
MessagesFile file = new MessagesFile();
file.setMessages(messages);
objectMapper.writerWithDefaultPrettyPrinter().writeValue(path.toFile(), file);
} catch (IOException e) {
throw new BusinessException("ai.chat.history.persistMessagesFailed", new Object[]{path, e.getMessage()}, e);
}
}
private void touchSession(Long userId, String sessionId) {
List<AiChatSession> sessions = loadSessions(userId);
sessions.stream()
.filter(s -> Objects.equals(s.getId(), sessionId))
.findFirst()
.ifPresent(s -> s.setGmtModified(LocalDateTime.now()));
persistSessions(userId, sessions);
}
@Data
public static class SessionsFile {
private List<AiChatSession> sessions = new ArrayList<>();
}
@DataView on GitHub (pinned to 5ee1e990e7)
Solutions
- Confirm read+write+execute permission on <basePath>/ai-chat-history for the process user and free space/inodes.
- Point chat2db.base.path at a writable volume.
- Use an atomic write (temp + ATOMIC_MOVE) so partial writes never replace a good file on a transient failure.
- Surface the failure to the user so they know the last message was not persisted.
Example fix
// before: direct write, partial on failure
objectMapper.writerWithDefaultPrettyPrinter().writeValue(path.toFile(), file);
// after: atomic, and notify on failure
try {
Path tmp = path.resolveSibling(path.getFileName() + ".tmp");
objectMapper.writerWithDefaultPrettyPrinter().writeValue(tmp.toFile(), file);
Files.move(tmp, path, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
notifyUser("message could not be saved");
throw e;
} Defensive patterns
Strategy: validation
Validate before calling
Path dir = Paths.get(ConfigUtils.getBasePath(), "ai-chat-history");
if (!Files.isWritable(dir)) {
throw new IllegalStateException("ai-chat-history not writable");
} Try / catch
try {
history.addMessage(...);
} catch (BusinessException e) {
if ("ai.chat.history.persistMessagesFailed".equals(e.getCode())) {
notifyUser("your last message could not be saved; retry");
return ResponseEntity.status(507).build();
}
throw e;
} Prevention
- Monitor free space on the data volume.
- Use atomic writes so a transient failure never clobbers a good file.
- Tell the user when a message was not persisted so they can resend.
When it happens
Trigger: Files.createDirectories(parent) fails or Jackson writeValue throws IOException: disk full, quota exceeded, read-only mount, permission denied, or the parent dir was removed during the call.
Common situations: Disk full mid-conversation; the process user lost write permission on ai-chat-history; read-only container volume; inode exhaustion.
Related errors
- ai.chat.history.persistSessionsFailed
- ai.chat.history.deleteMessagesFailed
- ai.attachment.localParseFailed
- ai.chat.history.loadSessionsFailed
- ai.chat.history.loadMessagesFailed
AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14).
Data as JSON: /api/errors/8650cbe017e014d8.
Report an issue: GitHub.