Problem Description
In a distributed/containerized deployment where a master daemon (unified_daemon.py) handles background tasks 24/7 while remote or separate client worker processes invoke MCP tools (e.g., list_recent), the client process frequently crashes with:
sqlite3.OperationalError: database is locked
This occurs because every cold MCP sub‑process aggressively re‑initializes the database, colliding with the write‑locks already held by the master daemon.
Root Cause Analysis
The flaw is inside superlocalmemory/mcp/server.py in the get_engine() singleton factory:
python
def get_engine():
global _engine
if _engine is not None:
return _engine
with _engine_lock:
if _engine is not None:
return _engine
...
config = SLMConfig.load()
new_engine = MemoryEngine(config, capabilities=Capabilities.LIGHT)
new_engine.initialize() # <--- ARCHITECTURAL BUG
_engine = new_engine
return _engine
_engine_lock is an in‑process lock – it cannot coordinate between the persistent daemon and separate MCP worker processes.
Every cold worker sees _engine as None and unconditionally calls new_engine.initialize(), which executes heavy DDL (create_all_tables) on an already‑locked SQLite database.
This directly collides with the daemon’s write operations, causing immediate deadlocks.
Error Traceback
text
2026-06-21 04:07:52,075 Processing request of type CallToolRequest
2026-06-21 04:07:57,083 list_recent failed
Traceback (most recent call last):
File "…/mcp/tools_core.py", line 337, in list_recent
engine = get_engine()
File "…/mcp/server.py", line 64, in get_engine
new_engine.initialize()
File "…/core/engine.py", line 125, in initialize
self._init_db_layer()
File "…/core/engine.py", line 150, in _init_db_layer
self._db.initialize(schema)
File "…/storage/database.py", line 123, in initialize
schema_module.create_all_tables(conn)
File "…/storage/schema.py", line 713, in create_all_tables
conn.executescript(ddl)
sqlite3.OperationalError: database is locked
Proposed Fix
Intercept the lock contention gracefully, skip redundant DDL, and allow the worker to reuse the existing database connection:
python
import sqlite3
import logging
logger = logging.getLogger("superlocalmemory")
def get_engine():
global _engine
if _engine is not None:
return _engine
with _engine_lock:
if _engine is not None:
return _engine
…
new_engine = MemoryEngine(config, capabilities=Capabilities.LIGHT)
# --- SAFE DISTRIBUTED PATCH ---
try:
new_engine.initialize()
except sqlite3.OperationalError as e:
if "locked" in str(e).lower():
logger.warning(
"Database locked by master daemon; "
"skipping redundant schema init and reusing existing connection."
)
pass
else:
raise
# --------------------------------
_engine = new_engine
return _engine
Environment
SLM Version: superlocalmemory 3.6.16 (verified via slm -v)
Python: 3.13+
Host: Linux SuperLocalMemory 7.0.2-2-pve, Proxmox VE 9.2.3
Topology: Multi‑LXC distributed cluster
CT 111 (192.168.50.140) – llama.cpp
CT 111 (192.168.50.143) – MCP Hub proxy
CT 106 (192.168.50.142) – OpenClaw frontend
CT 113 (192.168.50.144) – SuperLocalMemory server (24/7 daemon)
Database: SQLite, ~41 MB, under sustained concurrent read/write load
Additional Context
This issue is distinct from the database is locked errors that occur under heavy background task concurrency (which I’ve reported separately). Here, the crash is architectural – the get_engine() design assumes a single‑process environment and cannot safely coexist with a persistent daemon in a distributed deployment.
Thank you for your work on SLM – it has become a core part of my daily workflow. I’m happy to provide additional logs or testing feedback if needed.
Best regards,
sinking
Problem Description
In a distributed/containerized deployment where a master daemon (unified_daemon.py) handles background tasks 24/7 while remote or separate client worker processes invoke MCP tools (e.g., list_recent), the client process frequently crashes with:
sqlite3.OperationalError: database is locked
This occurs because every cold MCP sub‑process aggressively re‑initializes the database, colliding with the write‑locks already held by the master daemon.
Root Cause Analysis
The flaw is inside superlocalmemory/mcp/server.py in the get_engine() singleton factory:
python
def get_engine():
global _engine
if _engine is not None:
return _engine
with _engine_lock:
if _engine is not None:
return _engine
...
config = SLMConfig.load()
new_engine = MemoryEngine(config, capabilities=Capabilities.LIGHT)
new_engine.initialize() # <--- ARCHITECTURAL BUG
_engine = new_engine
return _engine
_engine_lock is an in‑process lock – it cannot coordinate between the persistent daemon and separate MCP worker processes.
Every cold worker sees _engine as None and unconditionally calls new_engine.initialize(), which executes heavy DDL (create_all_tables) on an already‑locked SQLite database.
This directly collides with the daemon’s write operations, causing immediate deadlocks.
Error Traceback
text
2026-06-21 04:07:52,075 Processing request of type CallToolRequest
2026-06-21 04:07:57,083 list_recent failed
Traceback (most recent call last):
File "…/mcp/tools_core.py", line 337, in list_recent
engine = get_engine()
File "…/mcp/server.py", line 64, in get_engine
new_engine.initialize()
File "…/core/engine.py", line 125, in initialize
self._init_db_layer()
File "…/core/engine.py", line 150, in _init_db_layer
self._db.initialize(schema)
File "…/storage/database.py", line 123, in initialize
schema_module.create_all_tables(conn)
File "…/storage/schema.py", line 713, in create_all_tables
conn.executescript(ddl)
sqlite3.OperationalError: database is locked
Proposed Fix
Intercept the lock contention gracefully, skip redundant DDL, and allow the worker to reuse the existing database connection:
python
import sqlite3
import logging
logger = logging.getLogger("superlocalmemory")
def get_engine():
global _engine
if _engine is not None:
return _engine
with _engine_lock:
if _engine is not None:
return _engine
…
new_engine = MemoryEngine(config, capabilities=Capabilities.LIGHT)
Environment
SLM Version: superlocalmemory 3.6.16 (verified via slm -v)
Python: 3.13+
Host: Linux SuperLocalMemory 7.0.2-2-pve, Proxmox VE 9.2.3
Topology: Multi‑LXC distributed cluster
CT 111 (192.168.50.140) – llama.cpp
CT 111 (192.168.50.143) – MCP Hub proxy
CT 106 (192.168.50.142) – OpenClaw frontend
CT 113 (192.168.50.144) – SuperLocalMemory server (24/7 daemon)
Database: SQLite, ~41 MB, under sustained concurrent read/write load
Additional Context
This issue is distinct from the database is locked errors that occur under heavy background task concurrency (which I’ve reported separately). Here, the crash is architectural – the get_engine() design assumes a single‑process environment and cannot safely coexist with a persistent daemon in a distributed deployment.
Thank you for your work on SLM – it has become a core part of my daily workflow. I’m happy to provide additional logs or testing feedback if needed.
Best regards,
sinking