The problem is that every time I restart my application, all the conversation history gets lost. I want to store the ConversationBufferMemory() data somewhere (like a file or database) and then load it back when the app starts again.
ValidationError: 6 validation errors for ChatMessageHistory
messages -> 0
Can't instantiate abstract class BaseMessage with abstract method type (type=type_error)
What’s the correct approach to make conversation memory persistent? Any working examples would be really helpful.
Use langchain’s RedisChatMessageHistory - don’t build your own. It’s way cleaner than manually handling JSON serialization and automatically deals with BaseMessage objects. Just give it your redis connection and session_id. No validation errors, works right away.
The BaseMessage serialization error happens because you’re trying to recreate abstract message objects. I’ve dealt with this mess plenty of times.
Skip the dict approach entirely and extract the raw message content:
# Save memory
messages = chat_session.memory.chat_memory.messages
save_data = []
for msg in messages:
save_data.append({
'type': msg.__class__.__name__,
'content': msg.content
})
# Write to file
import json
with open('memory.json', 'w') as f:
json.dump(save_data, f)
Then restore it:
from langchain.schema import HumanMessage, AIMessage
from langchain.memory.chat_message_histories import ChatMessageHistory
# Load from file
with open('memory.json', 'r') as f:
save_data = json.load(f)
# Rebuild messages
restored_messages = []
for msg_data in save_data:
if msg_data['type'] == 'HumanMessage':
restored_messages.append(HumanMessage(content=msg_data['content']))
elif msg_data['type'] == 'AIMessage':
restored_messages.append(AIMessage(content=msg_data['content']))
# Create new memory with restored history
restored_history = ChatMessageHistory(messages=restored_messages)
new_memory = ConversationBufferMemory(chat_memory=restored_history)
# Use in new conversation chain
chat_session = ConversationChain(llm=chat_model, memory=new_memory)
This works because you’re creating concrete message objects instead of trying to deserialize abstract ones. I use SQLite for production apps instead of JSON files.
I hit this exact issue a few months ago. Your Pydantic approach won’t work because BaseMessage is abstract - you can’t instantiate it directly from a dict. I switched to LangChain’s built-in serialization methods instead of manual Pydantic serialization. Use save_context and load_memory_variables with custom storage. I wrote a simple wrapper that saves the memory buffer to JSON after each conversation and loads it on startup. The trick is iterating through messages and recreating them as proper HumanMessage and AIMessage objects instead of deserializing BaseMessage directly. Another approach that worked great was switching to ConversationSummaryBufferMemory with Redis backend. It handles persistence automatically - no manual serialization headaches. Redis integration is straightforward and scales way better than file storage if you’re handling multiple users.
I switched to SQLAlchemy with custom message storage tables after hitting the same serialization headaches. Skip fighting LangChain’s memory objects - just store messages directly in a database with session_id, message_type, content, and timestamp columns. When starting a new conversation, I pull that session’s history from the database and rebuild ConversationBufferMemory using fresh HumanMessage and AIMessage instances. You get complete control over persistence and dodge those abstract class validation errors. Plus the database handles multiple sessions way better than files, and you can easily add conversation search or user analytics down the road. Performance stays solid even with thousands of messages per session.
Had the same serialization nightmare when scaling chatbots. Gave up on manual memory persistence after too many headaches.
Latenode changed everything for me. Set up workflows that auto-capture chat interactions, dump them into your database, and pull context back when sessions restart.
Best part? It handles all the message conversion and serialization mess automatically. Define the flow once - capture, store, retrieve - and you’re done.
Built several production bots this way. One workflow triggers on user messages and saves state, another loads history on session start. No more ValidationError hell or JSON parsing nightmares.
Bonus: built-in error handling plus easy additions like conversation analytics or session management down the road.