odysseus-dev/odysseus · error · HTTPException
Memory store is temporarily unreadable — nothing was importe
Error message
Memory store is temporarily unreadable — nothing was imported.
What it means
HTTP 503 raised by POST /api/import when memory_manager.load_all_for_update() raises MemoryStoreUnreadable. The import path deliberately refuses to merge into an unreadable store: a naive merge would write only the incoming rows and silently drop all existing memories. 503 signals a transient server-side store problem — nothing was imported.
Source
Thrown at routes/backup_routes.py:86
try:
body = await request.json()
except Exception:
raise HTTPException(400, "Invalid JSON")
if not isinstance(body, dict):
raise HTTPException(400, "Expected a JSON object")
imported = []
# ── Memories ──
if "memories" in body and isinstance(body["memories"], list):
# Strict load: importing on top of an unreadable store would write
# only the incoming rows back and drop everything already saved.
try:
existing = memory_manager.load_all_for_update()
except MemoryStoreUnreadable as e:
logger.error("Refusing to import memories: %s", e)
raise HTTPException(
503, "Memory store is temporarily unreadable — nothing was imported."
)
# Dedup against THIS user's own memories only. Using every tenant's
# rows (load_all) meant a memory whose text matched any other
# user's was silently skipped, so the importing user lost their own
# data. The full store is still saved back below.
existing_texts = {e.get("text", "").strip().lower()
for e in existing if e.get("owner") == user}
added = 0
for mem in body["memories"]:
if not isinstance(mem, dict) or not mem.get("text"):
continue
if mem["text"].strip().lower() in existing_texts:
continue # skip duplicates
# Assign owner when auth is enabled
if user and not mem.get("owner"):
mem["owner"] = user
existing.append(mem)View on GitHub (pinned to f9235ebbf1)
Solutions
- Retry the import after the store becomes readable (check the server log line 'Refusing to import memories').
- Resolve the underlying store issue: lock contention, file permissions, or corruption repair.
- Keep the export file — nothing was merged, so a clean retry is safe.
- Do not attempt to 'force' the import by clearing the store; that is exactly the data-loss path the guard prevents.
Defensive patterns
Strategy: retry
Try / catch
catch (e) {
if (e.status === 503) { scheduleRetry(seconds(30)); /* keep export file, nothing was merged */ }
else throw e;
} Prevention
- Treat 503 as transient: back off and retry later, never restructure the payload.
- Check server logs for 'Refusing to import memories' to confirm the store cause.
- Avoid importing while other writes to the memory store are running.
- Never delete the memory store to 'fix' an import — that is the data-loss scenario the guard blocks.
When it happens
Trigger: POST /api/import (with a 'memories' list) while the memory store file/database is locked, corrupt, or otherwise unreadable (MemoryStoreUnreadable). Concurrent write, disk issue, or a partially-written store file.
Common situations: Importing while another process holds the store; store file corrupted after a crash mid-write; permissions changed on the data directory; importing immediately after an unclean shutdown.
Related errors
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/bd12af9a51418fb1.
Report an issue: GitHub.